Files
tp/main_dc/yalarba/api_yal/documentation/README.md
T
valitovgaziz 75198ed00f docs: add integration test run instructions to README.md
- Added section 8 'Тестирование' with run instructions, structure, features, and diagnostics
- Also includes test file route path adjustments and import reordering
2026-06-12 08:46:20 +05:00

1407 lines
31 KiB
Markdown

# Документация API 1.0.2 last modifay 07/06/2026
## Базовый URL
```
https://easysite102.ru/api_yal/api/v1
```
## Аутентификация
Для доступа к защищенным эндпоинтам требуется JWT токен. Токен передается в заголовке:
```
Authorization: Bearer <token>
```
Refresh token хранится в **HttpOnly cookie**.
---
## 1. Аутентификация (Auth)
### 1.1 Регистрация пользователя
**POST** `/auth/register`
Создает новый аккаунт пользователя.
**Request Body:**
```json
{
"email": "user@example.com",
"password": "password123",
"first_name": "Иван",
"last_name": "Иванов"
}
```
| Поле | Тип | Обязательное | Описание |
|------|-----|--------------|----------|
| email | string | ✅ | Email пользователя |
| password | string | ✅ | Пароль, минимум 6 символов |
| first_name | string | ✅ | Имя |
| last_name | string | ✅ | Фамилия |
**Response (201 Created):**
```json
{
"token": "jwt_token_string",
"expires_at": "2024-01-01T00:00:00Z",
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "Иван",
"last_name": "Иванов",
"full_name": "Иван Иванов",
"role": "user"
}
}
```
---
### 1.2 Вход в систему
**POST** `/auth/login`
Аутентификация пользователя.
**Request Body:**
```json
{
"email": "user@example.com",
"password": "password123"
}
```
**Response (200 OK):**
```json
{
"token": "jwt_token_string",
"expires_at": "2024-01-01T00:00:00Z",
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "Иван",
"last_name": "Иванов",
"full_name": "Иван Иванов",
"role": "user"
}
}
```
*Refresh token устанавливается в HttpOnly cookie.*
---
### 1.3 Обновление токена
**POST** `/auth/refresh`
Обновляет access token с использованием refresh token.
**Cookie Required:** `refresh_token`
**Request Body (опционально, для мобильных приложений):**
```json
{
"refresh_token": "refresh_token_string"
}
```
**Response (200 OK):**
```json
{
"token": "new_jwt_token_string",
"expires_at": "2024-01-01T00:00:00Z",
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "Иван",
"last_name": "Иванов",
"full_name": "Иван Иванов",
"role": "user"
}
}
```
---
### 1.4 Выход из системы
**POST** `/auth/logout`
Завершает сессию пользователя.
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):**
```json
{
"message": "Successfully logged out"
}
```
---
### 1.5 Запрос сброса пароля
**POST** `/auth/password-reset/request`
Отправляет ссылку для сброса пароля (в тестовом режиме возвращает токен).
**Request Body:**
```json
{
"email": "user@example.com"
}
```
**Response (200 OK):**
```json
{
"message": "Password reset link has been sent to your email",
"token": "reset_token" // только в тестовом режиме
}
```
---
### 1.6 Подтверждение сброса пароля
**POST** `/auth/password-reset/confirm`
Устанавливает новый пароль.
**Request Body:**
```json
{
"token": "reset_token",
"new_password": "new_password123"
}
```
**Response (200 OK):**
```json
{
"message": "Password has been successfully reset"
}
```
---
### 1.7 Вход для мобильных приложений
**POST** `/auth/mobile/login`
Альтернативный эндпоинт для мобильных клиентов.
**Request Body:**
```json
{
"email": "user@example.com",
"password": "password123"
}
```
**Response (200 OK):**
```json
{
"access_token": "jwt_token",
"refresh_token": "refresh_token_string",
"expires_at": "2024-01-01T00:00:00Z",
"user": {
"id": 1,
"email": "user@example.com",
"first_name": "Иван",
"last_name": "Иванов",
"full_name": "Иван Иванов",
"role": "user"
}
}
```
---
## 2. Аккаунт (Account)
### 2.1 Получение профиля пользователя
**GET** `/account/profile`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):**
```json
{
"id": 1,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"email": "user@example.com",
"full_name": "Иван Иванов",
"first_name": "Иван",
"last_name": "Иванов",
"phone": "+79991234567",
"city": "Москва",
"organization_form": "ООО",
"organization_name": "Организация",
"organization_short": "ООО Орг",
"inn": "1234567890",
"personal_inn": "",
"is_active": true,
"is_verified": false,
"role": "user",
"stats": {
"objects_count": 5,
"feedbacks_count": 12,
"comments_count": 34,
"ratings_count": 8,
"appeals_count": 3
}
}
```
---
### 2.2 Получение аккаунта по ID (свой профиль)
**GET** `/account`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):**
```json
{
"id": 1,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"email": "user@example.com",
"full_name": "Иван Иванов",
"first_name": "Иван",
"last_name": "Иванов",
"phone": "+79991234567",
"city": "Москва",
"is_active": true,
"is_verified": false,
"role": "user"
}
```
---
### 2.3 Обновление аккаунта
**PUT** `/account`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"full_name": "Иван Петрович Иванов",
"first_name": "Иван",
"last_name": "Иванов",
"phone": "+79991234567",
"city": "Санкт-Петербург",
"organization_form": "ИП",
"organization_name": "ИП Иванов",
"organization_short": "ИП Иванов",
"inn": "123456789012",
"personal_inn": "123456789012"
}
```
**Response (200 OK):** (тот же формат, что и `AccountResponse`)
---
### 2.4 Смена пароля
**POST** `/account/change-password`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"current_password": "old_password",
"new_password": "new_password123"
}
```
**Response (200 OK):**
```json
{
"message": "Password changed successfully"
}
```
---
### 2.5 Удаление аккаунта
**DELETE** `/account`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):**
```json
{
"message": "Account deleted successfully"
}
```
---
### 2.6 Список аккаунтов (админ/модератор)
**GET** `/admin/accounts`
**Headers:** `Authorization: Bearer <token>` (требуются права admin)
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| page | int | Номер страницы (default: 1) |
| page_size | int | Размер страницы (default: 20, max: 100) |
| search | string | Поиск по email и имени |
| role | string | Фильтр по роли (user/admin/moderator) |
| is_active | bool | Фильтр по статусу активности |
**Response (200 OK):**
```json
{
"items": [...],
"total": 100,
"page": 1,
"page_size": 20,
"total_pages": 5
}
```
---
### 2.7 Верификация аккаунта (админ)
**PUT** `/admin/accounts/verify`
**Headers:** `Authorization: Bearer <token>` (требуются права admin)
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| id | uint | ✅ ID аккаунта |
**Request Body:**
```json
{
"is_verified": true
}
```
**Response (200 OK):**
```json
{
"message": "Account verified successfully"
}
```
---
### 2.8 Обновление статуса аккаунта (админ)
**PUT** `/admin/accounts/status`
**Headers:** `Authorization: Bearer <token>` (требуются права admin)
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| id | uint | ✅ ID аккаунта |
**Request Body:**
```json
{
"is_active": true,
"role": "moderator"
}
```
**Response (200 OK):**
```json
{
"message": "Account status updated successfully"
}
```
---
## 3. Объекты (Objects)
### 3.1 Создание объекта
**POST** `/objects`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"short_name": "Кафе Уют",
"long_name": "Кафе Уют на Невском",
"type": "cafe",
"phone": "+78121234567",
"email": "cafe@example.com",
"site": "https://cafe.example.com",
"short_description": "Уютное кафе в центре",
"description": "Подробное описание кафе",
"address": "г. Санкт-Петербург, Невский пр., 1",
"latitude": 59.9343,
"longitude": 30.3351,
"is_active": true,
"is_verified": false
}
```
**Response (201 Created):** `ObjectResponse`
---
### 3.2 Получение объекта по ID
**GET** `/objects/{id}`
**Response (200 OK):** `ObjectResponse`
```json
{
"id": 1,
"created_at": "2024-01-01T00:00:00Z",
"updated_at": "2024-01-01T00:00:00Z",
"deleted_at": null,
"owner_id": 1,
"owner": {
"id": 1,
"email": "user@example.com",
"full_name": "Иван Иванов",
"first_name": "Иван",
"last_name": "Иванов"
},
"short_name": "Кафе Уют",
"long_name": "Кафе Уют на Невском",
"type": "cafe",
"phone": "+78121234567",
"email": "cafe@example.com",
"site": "https://cafe.example.com",
"short_description": "Уютное кафе в центре",
"description": "Подробное описание кафе",
"address": "г. Санкт-Петербург, Невский пр., 1",
"latitude": 59.9343,
"longitude": 30.3351,
"is_active": true,
"is_verified": false,
"feedback_count": 15,
"tourist_rating": {
"id": 1,
"created_at": "...",
"platform": "tourist",
"average_score": 4.5,
"total_votes": 10,
"vote_breakdown": {...}
},
"entrepreneur_rating": {...},
"feedbacks": [...]
}
```
---
### 3.3 Обновление объекта
**PUT** `/objects/{id}`
**Headers:** `Authorization: Bearer <token>`
**Request Body:** (все поля опциональны)
```json
{
"short_name": "Кафе Уютное",
"description": "Обновленное описание",
"is_active": false
}
```
**Response (200 OK):** `ObjectResponse`
---
### 3.4 Удаление объекта
**DELETE** `/objects/{id}`
**Headers:** `Authorization: Bearer <token>`
**Response (204 No Content)**
---
### 3.5 Список объектов (с фильтрацией)
**GET** `/objects`
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| page | int | Номер страницы (default: 1) |
| page_size | int | Размер страницы (default: 10) |
| type | string | Фильтр по типу объекта |
| q | string | Поиск по названию |
| is_active | bool | Фильтр по активности |
**Response (200 OK):** `ObjectListResponse`
---
### 3.6 Объекты пользователя
**GET** `/objects/owner/{ownerId}`
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| page | int | Номер страницы (default: 1) |
| page_size | int | Размер страницы (default: 10) |
**Response (200 OK):** `ObjectListResponse`
---
### 3.7 Поиск объектов
**GET** `/objects/search`
**Query Parameters:**
| Параметр | Тип | Обязательное | Описание |
|----------|-----|--------------|----------|
| q | string | ✅ | Поисковый запрос |
| page | int | Номер страницы (default: 1) |
| page_size | int | Размер страницы (default: 10) |
**Response (200 OK):** `ObjectListResponse`
---
### 3.8 Ближайшие объекты
**GET** `/objects/nearby`
**Query Parameters:**
| Параметр | Тип | Обязательное | Описание |
|----------|-----|--------------|----------|
| lat | float | ✅ | Широта |
| lng | float | ✅ | Долгота |
| radius | float | Радиус в метрах (default: 1000) |
| page | int | Номер страницы (default: 1) |
| page_size | int | Размер страницы (default: 10) |
**Response (200 OK):** `ObjectListResponse`
---
### 3.9 Создание отзыва об объекте
**POST** `/objects/{id}/feedbacks`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"platform": "tourist",
"score": 5,
"text": "Отличное место!"
}
```
| Поле | Тип | Обязательное | Описание |
|------|-----|--------------|----------|
| platform | string | ✅ | `entrepreneur` или `tourist` |
| score | int | ✅ | Оценка от 1 до 5 |
| text | string | ✅ | Текст отзыва |
**Response (201 Created):** `FeedbackResponse`
---
### 3.10 Голосование за объект
**POST** `/objects/{id}/ratings`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"platform": "tourist",
"score": 5
}
```
**Response (201 Created):** `RatingVoteResponse`
---
## 4. Отзывы (Feedbacks)
### 4.1 Создание отзыва
**POST** `/feedbacks`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"object_id": 1,
"rating": 5,
"text": "Отличное место!",
"platform": "tourist",
"media_urls": ["https://example.com/photo1.jpg"]
}
```
| Поле | Тип | Обязательное | Описание |
|------|-----|--------------|----------|
| object_id | uint | ✅ | ID объекта |
| rating | int | ✅ | Оценка от 1 до 5 |
| text | string | ✅ | Текст отзыва, мин 1, макс 2000 символов |
| platform | string | ✅ | `entrepreneur` или `tourist` |
| media_urls | []string | Список URL медиафайлов |
**Response (201 Created):** `FeedbackResponse`
---
### 4.2 Получение отзыва по ID
**GET** `/feedbacks/{id}`
**Response (200 OK):** `FeedbackResponse`
---
### 4.3 Обновление отзыва
**PUT** `/feedbacks/{id}`
**Headers:** `Authorization: Bearer <token>`
**Request Body:** (все поля опциональны)
```json
{
"rating": 4,
"text": "Обновленный текст отзыва"
}
```
**Response (200 OK):** `FeedbackResponse`
---
### 4.4 Удаление отзыва
**DELETE** `/feedbacks/{id}`
**Headers:** `Authorization: Bearer <token>`
**Response (204 No Content)**
---
### 4.5 Список отзывов
**GET** `/feedbacks`
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| offset | int | Смещение (default: 0) |
| limit | int | Лимит (default: 20, max: 100) |
**Response (200 OK):** `FeedbackListResponse`
---
### 4.6 Мои отзывы
**GET** `/feedbacks/my`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):** `FeedbackListResponse`
---
### 4.7 Отзывы по объекту
**GET** `/feedbacks/object/{objectID}`
**Response (200 OK):** `FeedbackListResponse`
---
### 4.8 Отзывы по платформе
**GET** `/feedbacks/platform/{platform}`
| Параметр | Описание |
|----------|----------|
| platform | `entrepreneur` или `tourist` |
**Response (200 OK):** `FeedbackListResponse`
---
### 4.9 Поиск отзывов
**GET** `/feedbacks/search`
**Query Parameters:**
| Параметр | Тип | Обязательное | Описание |
|----------|-----|--------------|----------|
| q | string | ✅ | Поисковый запрос |
**Response (200 OK):** `FeedbackListResponse`
---
### 4.10 Статистика отзывов
**GET** `/feedbacks/stats`
**Response (200 OK):**
```json
{
"total_feedbacks": 1000,
"average_rating": 4.2,
"rating_distribution": {
"1": 50,
"2": 100,
"3": 200,
"4": 300,
"5": 350
},
"platform_stats": {
"tourist": 600,
"entrepreneur": 400
}
}
```
---
### 4.11 Комментарии к отзыву
**GET** `/feedbacks/{id}/comments`
**Response (200 OK):** `CommentListResponse`
---
### 4.12 Добавление комментария к отзыву
**POST** `/feedbacks/{id}/comments`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"text": "Отличный отзыв, согласен!"
}
```
**Response (201 Created):** `CommentResponse`
---
### 4.13 Обновление комментария
**PUT** `/feedbacks/{id}/comments/{commentID}`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"text": "Обновленный текст комментария"
}
```
**Response (200 OK):**
```json
{
"message": "comment updated successfully"
}
```
---
### 4.14 Удаление комментария
**DELETE** `/feedbacks/{id}/comments/{commentID}`
**Headers:** `Authorization: Bearer <token>`
**Response (204 No Content)**
---
## 5. Обращения (Appeals)
### 5.1 Создание обращения
**POST** `/appeals`
**Headers:** `Authorization: Bearer <token>` (опционально для анонимных)
**Request Body:**
```json
{
"type": "complaint",
"title": "Проблема с заказом",
"message": "Подробное описание проблемы",
"priority": "high",
"object_id": 1,
"feedback_id": 1,
"comment_id": 1,
"contact_name": "Иван Иванов",
"contact_email": "ivan@example.com",
"contact_phone": "+79991234567",
"attachments": ["url1", "url2"],
"category": "technical",
"labels": ["bug", "urgent"],
"custom_data": {
"order_id": 12345
}
}
```
| Поле | Тип | Обязательное | Описание |
|------|-----|--------------|----------|
| type | string | ✅ | `complaint`, `suggestion`, `wish`, `question`, `other` |
| title | string | ✅ | Заголовок, 3-255 символов |
| message | string | ✅ | Сообщение, минимум 10 символов |
| priority | string | `low`, `medium`, `high`, `critical` |
| contact_email | string | Должен быть валидным email, если указан |
**Response (201 Created):** `AppealResponse`
---
### 5.2 Получение обращения по ID
**GET** `/appeals/{id}`
**Headers:** `Authorization: Bearer <token>` (требуется для просмотра чужих обращений)
**Response (200 OK):** `AppealResponse`
---
### 5.3 Обновление обращения
**PUT** `/appeals/{id}`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"title": "Обновленный заголовок",
"message": "Обновленное сообщение",
"priority": "critical",
"category": "billing"
}
```
**Response (200 OK):** `AppealResponse`
---
### 5.4 Удаление обращения
**DELETE** `/appeals/{id}`
**Headers:** `Authorization: Bearer <token>`
**Response (204 No Content)**
---
### 5.5 Список обращений (админ/модератор)
**GET** `/appeals`
**Headers:** `Authorization: Bearer <token>` (требуются права admin/moderator)
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| offset | int | Смещение (default: 0) |
| limit | int | Лимит (default: 20, max: 100) |
| status | string | `new`, `in_progress`, `resolved`, `rejected`, `closed` |
| type | string | `complaint`, `suggestion`, `wish`, `question`, `other` |
| priority | string | `low`, `medium`, `high`, `critical` |
| search | string | Поиск по заголовку/сообщению |
**Response (200 OK):** `ListAppealsResponse`
---
### 5.6 Мои обращения
**GET** `/appeals/me`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):** `ListAppealsResponse`
---
### 5.7 Обращения пользователя (админ)
**GET** `/appeals/user/{userID}`
**Headers:** `Authorization: Bearer <token>` (требуются права admin)
**Response (200 OK):** `ListAppealsResponse`
---
### 5.8 Обновление статуса обращения
**PATCH** `/appeals/{id}/status`
**Headers:** `Authorization: Bearer <token>` (требуются права admin/moderator)
**Request Body:**
```json
{
"status": "in_progress",
"comment": "Начата обработка обращения"
}
```
**Response (200 OK):**
```json
{
"message": "Status updated successfully"
}
```
---
### 5.9 Назначение ответственного
**POST** `/appeals/{id}/assign`
**Headers:** `Authorization: Bearer <token>` (требуются права admin/moderator)
**Request Body:**
```json
{
"assigned_to_id": 5
}
```
**Response (200 OK):**
```json
{
"message": "Assigned successfully"
}
```
---
### 5.10 Решение обращения
**POST** `/appeals/{id}/resolve`
**Headers:** `Authorization: Bearer <token>` (требуются права admin/moderator)
**Request Body:**
```json
{
"resolution": "Проблема решена путем обновления настроек"
}
```
**Response (200 OK):**
```json
{
"message": "Appeal resolved successfully"
}
```
---
### 5.11 История изменений обращения
**GET** `/appeals/{id}/history`
**Response (200 OK):** `ListHistoryResponse`
---
### 5.12 Статистика обращений (админ)
**GET** `/appeals/statistics`
**Headers:** `Authorization: Bearer <token>` (требуются права admin)
**Response (200 OK):**
```json
{
"total": 1000,
"by_status": {
"new": 50,
"in_progress": 100,
"resolved": 800,
"rejected": 30,
"closed": 20
},
"by_type": {
"complaint": 400,
"suggestion": 200,
"wish": 150,
"question": 200,
"other": 50
},
"by_priority": {
"low": 200,
"medium": 500,
"high": 250,
"critical": 50
},
"by_category": {...},
"avg_resolve_time_hours": 24.5
}
```
---
## 6. Комментарии (Comments)
### 6.1 Создание комментария
**POST** `/comments`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"feedback_id": 1,
"text": "Отличный отзыв!",
"parent_id": null
}
```
| Поле | Тип | Обязательное | Описание |
|------|-----|--------------|----------|
| feedback_id | uint | ✅ | ID отзыва |
| text | string | ✅ | Текст комментария, 1-5000 символов |
| parent_id | uint | ID родительского комментария |
**Response (201 Created):** `CommentResponse`
---
### 6.2 Получение комментария по ID
**GET** `/comments/{id}`
**Response (200 OK):** `CommentResponse`
---
### 6.3 Обновление комментария
**PUT** `/comments/{id}`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"text": "Обновленный текст"
}
```
**Response (200 OK):** `CommentResponse`
---
### 6.4 Удаление комментария
**DELETE** `/comments/{id}`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):**
```json
{
"message": "Comment deleted successfully"
}
```
---
### 6.5 Список комментариев (с фильтрацией)
**GET** `/comments`
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| page | int | Номер страницы (default: 1) |
| page_size | int | Размер страницы (default: 20, max: 100) |
| feedback_id | uint | Фильтр по отзыву |
| author_id | uint | Фильтр по автору |
| parent_id | uint | Фильтр по родительскому комментарию |
| verified | bool | Фильтр по верификации |
| sort_by | string | Поле сортировки (default: created_at) |
| sort_order | string | `asc` или `desc` (default: desc) |
**Response (200 OK):**
```json
{
"data": [...],
"total": 100,
"page": 1,
"page_size": 20,
"total_pages": 5
}
```
---
### 6.6 Мои комментарии
**GET** `/comments/my`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):** (тот же формат, что и список)
---
### 6.7 Комментарии по отзыву
**GET** `/comments/feedback/{feedbackID}`
**Response (200 OK):** (тот же формат, что и список)
---
### 6.8 Ответы на комментарий
**GET** `/comments/replies/{parentID}`
**Response (200 OK):** (тот же формат, что и список)
---
### 6.9 Верификация комментария (админ)
**PUT** `/comments/{id}/verify`
**Headers:** `Authorization: Bearer <token>` (требуются права admin)
**Request Body:**
```json
{
"verified": true
}
```
**Response (200 OK):**
```json
{
"message": "Comment verified successfully"
}
```
---
### 6.10 Статистика комментариев
**GET** `/comments/stats`
**Response (200 OK):**
```json
{
"total_comments": 5000,
"verified_comments": 3000,
"unverified_comments": 2000,
"avg_comments_per_feedback": 5.2,
"most_active_users": [...]
}
```
---
## 7. Рейтинги (Ratings)
### 7.1 Создание рейтинга
**POST** `/ratings`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"object_id": 1,
"platform": "tourist"
}
```
**Response (201 Created):** `RatingResponse`
---
### 7.2 Получение рейтинга по ID
**GET** `/ratings/{id}`
**Response (200 OK):** `RatingResponse`
---
### 7.3 Получение рейтинга объекта по платформе
**GET** `/ratings/object/{objectID}/platform/{platform}`
| Параметр | Описание |
|----------|----------|
| platform | `entrepreneur` или `tourist` |
**Response (200 OK):** `RatingResponse`
---
### 7.4 Список рейтингов
**GET** `/ratings`
**Query Parameters:**
| Параметр | Тип | Описание |
|----------|-----|----------|
| page | int | Номер страницы (default: 1) |
| page_size | int | Размер страницы (default: 20) |
| platform | string | `entrepreneur` или `tourist` |
| owner_id | uint | Фильтр по владельцу |
| object_id | uint | Фильтр по объекту |
**Response (200 OK):** `ListRatingsResponse`
---
### 7.5 Голосование
**POST** `/ratings/{targetID}/vote/{platform}`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"score": 5
}
```
**Response (200 OK):** `RatingResponse`
---
### 7.6 Мой голос
**GET** `/ratings/{targetID}/my-vote/{platform}`
**Headers:** `Authorization: Bearer <token>`
**Response (200 OK):**
```json
{
"has_voted": true,
"user_score": 5
}
```
---
### 7.7 Обновление моего голоса
**PUT** `/ratings/{targetID}/my-vote/{platform}`
**Headers:** `Authorization: Bearer <token>`
**Request Body:**
```json
{
"score": 4
}
```
**Response (200 OK):** `RatingResponse`
---
### 7.8 Удаление моего голоса
**DELETE** `/ratings/{targetID}/my-vote/{platform}`
**Headers:** `Authorization: Bearer <token>`
**Response (204 No Content)**
---
### 7.9 Статистика рейтингов
**GET** `/ratings/stats`
**Response (200 OK):**
```json
{
"total_ratings": 500,
"total_votes": 5000,
"platform_distribution": {...},
"average_by_platform": {...}
}
```
---
## Коды ошибок
| Код | Описание |
|-----|----------|
| 200 | Успешный запрос |
| 201 | Успешное создание ресурса |
| 204 | Успешное удаление (нет содержимого) |
| 400 | Ошибка валидации или неверный запрос |
| 401 | Не авторизован |
| 403 | Доступ запрещен |
| 404 | Ресурс не найден |
| 409 | Конфликт (например, пользователь уже существует) |
| 500 | Внутренняя ошибка сервера |
**Формат ошибки:**
```json
{
"error": "Описание ошибки"
}
```
Для валидационных ошибок:
```json
{
"error": "Validation failed",
"fields": [
"field email is invalid: required",
"field password is invalid: min"
]
}
```
---
## 8. Тестирование
### 8.1 Запуск интеграционных тестов
Интеграционные тесты используют in-memory SQLite и mock-репозитории. Запуск:
```bash
cd main_dc/yalarba/api_yal
CGO_ENABLED=1 go test ./tests/integration/... -v -count=1
```
**Требования:**
- Go 1.21+
- `CGO_ENABLED=1` (используется `mattn/go-sqlite3`)
- Зависимости устанавливаются автоматически через `go mod download`
### 8.2 Структура тестов
```
tests/
├── integration/
│ ├── account_test.go # Тесты аккаунтов (профиль, обновление, удаление)
│ ├── appeal_test.go # Тесты обращений (CRUD, мои обращения)
│ ├── auth_test.go # Тесты аутентификации (регистрация, логин, refresh, logout, сброс пароля)
│ ├── comment_test.go # Тесты комментариев (CRUD, список, статистика)
│ ├── feedback_test.go # Тесты отзывов (CRUD, список, поиск, статистика)
│ ├── object_test.go # Тесты объектов (CRUD, поиск, nearby)
│ └── rating_test.go # Тесты рейтингов (голосование, статистика)
└── testutils/
├── fixtures.go # DTO и хелперы создания тестовых данных
├── mock_appeal_repository.go # Mock-репозиторий обращений (map-based)
├── mock_object_repository.go # Mock-репозиторий объектов (map-based)
├── setup.go # TestConfig, TestUser, HTTP-клиент
└── test_server.go # Chi-роутер, in-memory SQLite, middleware
```
### 8.3 Особенности
- **Общий сервер**: Все тесты в одном запуске используют один экземпляр `TestServer` (синглтон через `sync.Once`).
- **In-memory БД**: SQLite `file::memory:?cache=shared`, данные не сохраняются между запусками.
- **Mock-репозитории**: `ObjectRepository` и `AppealRepository` заменены на map-based реализации (избегают Haversine и jsonb-зависимостей).
- **Автоочистка**: Тестовые пользователи удаляются после каждого теста через `CleanupTestUser`.
- **Bearer-токены**: JWT токен создаётся при регистрации и передаётся в `Authorization` заголовке.
### 8.4 Диагностика
Для просмотра HTTP-логов сервера:
```bash
CGO_ENABLED=1 go test ./tests/integration/... -v -count=1 2>&1 | grep "\[ValitovGazizPC"
```
Фильтрация по конкретному тесту:
```bash
CGO_ENABLED=1 go test ./tests/integration/... -v -count=1 -run "TestAuthFlow/PasswordReset"
```