# Документация 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"
  ]
}
```