## Техническое задание на сервис «Календарь»

### Общее описание
Сервис "Календарь" представляет собой максимально упрощенный сервис для хранения календарных событий и оправки уведомлений.

Сервис предполагает:
* возможность добавить/обновить событие;
* возможность получить список событий на день/неделю/месяц;
* возможность получить уведомление за N дней до события.

Сервис НЕ предполагает:
* авторизации;
* разграничения доступа;
* web-интерфейса.

### Архитектура
Полностью завершенный сервис состоит из 5 процессов.

#### 1) API
API предоставляет собой GRPC и HTTP интерфейсы для пользователей. API реализуют основные методы сервиса.
Так как авторизация и разделение доступа выходят за рамки сервиса, мы предполагаем, что ID пользователя
просто передается через параметры / метаданные / заголовок запроса.

#### 2) Планировщик
Планировщик - это фоновый процесс, который не взаимодействует с пользователем и выполняет периодические задания:
* выбор событий, требующих уведомления и отправка уведомлений в очередь рассыльщику;
* очистка старых (более 1 года назад) событий.

#### 3) Рассыльщик
Рассыльщик - это фоновый процесс, занимающийся отправкой уведомлений.

В рамках задания нет необходимости реальной отправки сообщений, достаточно, если рассыльщик просто будет
записывать их в лог / выводить в STDOUT.

#### 4) СУБД
Реляционная СУБД (например, PostgreSQL) - хранит информацию о событиях.

### 5) Очередь сообщений
Очередь сообщений (RabbitMQ) - используется для передачи уведомлений от Планировщика Рассыльщику.

### Описание сущностей
#### Событие
Событие - основная сущность, содержит в себе поля:
* ID - уникальный идентификатор события (можно воспользоваться UUID);
* Заголовок - короткий текст;
* Дата и время события;
* Длительность события (или дата и время окончания);
* Описание события - длинный текст, опционально;
* ID пользователя, владельца события;
* За сколько времени высылать уведомление, опционально.

#### Уведомление
Уведомление - временная сущность, в БД не хранится, складывается в очередь для рассыльщика, содержит поля:
* ID события;
* Заголовок события;
* Дата события;
* Пользователь, которому отправлять.

### Описание методов
* Создать (событие);
* Обновить (ID события, событие);
* Удалить (ID события);
* СписокСобытийНаДень (дата);
* СписокСобытийНаНеделю (дата начала недели);
* СписокСобытийНеМесяц (дата начала месяца).

### Конфигурация, логирование, контейнеризация
Рекомендуется собирать проект в виде трех бинарных файлов, по одному на каждый микросервис.
Каждый из сервисов должен принимать путь файлу конфигурации:
```text
./calendar           --config=/path/to/calendar_config.yaml
./calendar_scheduler --config=/path/to/scheduler_config.yaml
./calendar_sender    --config=/path/to/sender_config.yaml
```
Проект следует оформить в виде набора контейнеров для каждого из микросервисов.
Поскольку запуск будет осуществлять в контейнерах - логи нужно печатать в STDERR.
Сервисы должны получать настройки (например, адрес и логин в СУБД) через переменные окружения.
При желании можно использовать конфиг viper, с поддержкой переменных окружения.

Развертывание микросервиса должно осуществляться командой `docker-compose up` в директории с проектом.

### Тестирование
Для проекта необходимо реализовать интеграционные тесты, т.е. тесты проверяющие работу на уровне API.
Интеграционные тесты можно создать с помощью BDD, а можно просто с помощью стандартного пакета `testing`
и запускать их в отдельном контейнере в том же compose окружении, что и остальные микросервисы.
В таком случае тесты смогут получать адрес работающего сервиса через переменные окружения, выполнять запросы к нему,
а также проверять состояние базы данных и пр.

### Этапы разработки
Разработка разделена на следующие этапы (ДЗ):
* Разрабатываем скелет сервиса: конфигурирование, работа с базой, простой web-сервер.
* Добавляем HTTP и GRPC API.
* Выдялем Планировщик и Рассыльщик. Интегрируемся с очередью сообщений.
* Создаем Docker-образы, docker-compose конфигурации, пишем интеграционные тесты.

Таким образом, на каждом этапе мы получаем осмысленный проект.
