### **Техническое задание №2: Базовое управление кампаниями и каналами (CRUD)**

**Цель:** Реализовать полную бизнес-логику и API для управления основными сущностями системы: **маркетинговыми кампаниями (`Campaign`)** и **каналами публикации (`Channel`)**. На этом этапе будет создана базовая административная функциональность, позволяющая создавать, просматривать, редактировать и удалять эти сущности через REST API.

---

## 1\. Data Transfer Objects (DTOs)

Для обеспечения чистоты и безопасности API необходимо создать DTO для всех входящих и исходящих данных.

### `CampaignDto.java`

Используется для возврата информации о кампании.

```java
public class CampaignDto {
    private UUID id;
    private String name;
    private String goal;
    private BigDecimal budget;
    private ZonedDateTime startAt;
    private ZonedDateTime endAt;
    private CampaignStatus status;
}
```

### `CreateCampaignRequest.java`

Используется для создания новой кампании.

```java
public class CreateCampaignRequest {
    @NotBlank
    private String name;
    private String goal;
    @PositiveOrZero
    private BigDecimal budget;
    @FutureOrPresent
    private ZonedDateTime startAt;
    @Future
    private ZonedDateTime endAt;
    private CampaignStatus status = CampaignStatus.PLANNED;
}
```

### `ChannelDto.java`

Используется для возврата информации о канале.

```java
public class ChannelDto {
    private UUID id;
    private String name;
    private ChannelType type;
    private boolean isActive;
}
```

### `CreateChannelRequest.java`

Используется для создания нового канала.

```java
public class CreateChannelRequest {
    @NotBlank
    private String name;
    @NotNull
    private ChannelType type;
    @NotBlank
    private String apiKeyRef;
    private boolean isActive = true;
}
```

---

## 2\. Сервисный слой (Business Logic)

### `CampaignService.java`

Сервис для управления кампаниями.

-   **Методы:**
    -   `List<CampaignDto> getAllCampaigns()`: Возвращает список всех кампаний.
    -   `CampaignDto getCampaignById(UUID id)`: Находит кампанию по ID. В случае отсутствия выбрасывает исключение `ResourceNotFoundException`.
    -   `CampaignDto createCampaign(CreateCampaignRequest request)`: Создает новую кампанию на основе DTO, сохраняет в БД и возвращает `CampaignDto`.
    -   `CampaignDto updateCampaign(UUID id, CreateCampaignRequest request)`: Обновляет существующую кампанию.
    -   `void deleteCampaign(UUID id)`: Удаляет кампанию по ID.

### `ChannelService.java`

Сервис для управления каналами.

-   **Методы:**
    -   `List<ChannelDto> getAllChannels()`: Возвращает список всех каналов.
    -   `ChannelDto getChannelById(UUID id)`: Находит канал по ID. В случае отсутствия выбрасывает исключение `ResourceNotFoundException`.
    -   `ChannelDto createChannel(CreateChannelRequest request)`: Создает новый канал.
    -   `ChannelDto updateChannel(UUID id, CreateChannelRequest request)`: Обновляет существующий канал.
    -   `void deleteChannel(UUID id)`: Удаляет канал по ID.

---

## 3\. API Endpoints (REST Controllers)

### `CampaignController.java`

Контроллер для управления кампаниями.

-   **`GET /api/smm/campaigns`**
    -   **Описание:** Получить список всех кампаний.
    -   **Ответ (200 OK):** `List<CampaignDto>`
-   **`GET /api/smm/campaigns/{id}`**
    -   **Описание:** Получить кампанию по ID.
    -   **Ответ (200 OK):** `CampaignDto`
    -   **Ответ (404 Not Found):** Если кампания не найдена.
-   **`POST /api/smm/campaigns`**
    -   **Описание:** Создать новую кампанию.
    -   **Тело запроса:** `CreateCampaignRequest`
    -   **Ответ (201 Created):** `CampaignDto`
-   **`PUT /api/smm/campaigns/{id}`**
    -   **Описание:** Обновить существующую кампанию.
    -   **Тело запроса:** `CreateCampaignRequest`
    -   **Ответ (200 OK):** `CampaignDto`
-   **`DELETE /api/smm/campaigns/{id}`**
    -   **Описание:** Удалить кампанию.
    -   **Ответ (204 No Content):** Успешное удаление.

### `ChannelController.java`

Контроллер для управления каналами.

-   **`GET /api/smm/channels`**
    -   **Описание:** Получить список всех каналов.
    -   **Ответ (200 OK):** `List<ChannelDto>`
-   **`POST /api/smm/channels`**
    -   **Описание:** Создать новый канал.
    -   **Тело запроса:** `CreateChannelRequest`
    -   **Ответ (201 Created):** `ChannelDto`
-   **Прочие эндпоинты (`GET /id`, `PUT /id`, `DELETE /id`)** реализуются по аналогии с `CampaignController`.

---

## 4\. Обработка ошибок

-   Необходимо создать глобальный обработчик исключений (`@ControllerAdvice`) для перехвата `ResourceNotFoundException` и возврата корректного HTTP-статуса `404 Not Found` с информативным сообщением в теле ответа.
-   Валидация DTO (`@NotBlank`, `@NotNull` и т.д.) должна быть включена с помощью аннотации `@Valid` в методах контроллера. При ошибке валидации Spring автоматически вернет статус `400 Bad Request`.

---

## Критерии выполнения

-   Созданы все указанные DTO с аннотациями для валидации.
-   Реализованы `CampaignService` и `ChannelService` со всей CRUD-логикой.
-   Реализованы `CampaignController` и `ChannelController` со всеми указанными REST-эндпоинтами.
-   Все эндпоинты корректно работают и возвращают ожидаемые HTTP-статусы и тела ответов.
-   Реализована обработка ошибок для случаев, когда сущность не найдена.
-   Код покрыт базовыми юнит-тестами для сервисного слоя.
