|
| 1 | +# Тестовое задание Авито: Сервис назначения ревьюверов на Pull Request'ы |
| 2 | + |
| 3 | +## Описание |
| 4 | + |
| 5 | +Веб-сервис для автоматического назначения ревьюверов на Pull Request'ы внутри команд разработки. Сервис предоставляет REST API для управления командами, пользователями, Pull Request'ами и получения статистики по назначениям ревьюверов. |
| 6 | + |
| 7 | +## Функциональность |
| 8 | + |
| 9 | +### Управление командами |
| 10 | +- **POST /team/add** - Создание команды с участниками (создаёт/обновляет пользователей) |
| 11 | +- **GET /team/get?team_name={name}** - Получение информации о команде и её участниках |
| 12 | + |
| 13 | +### Управление пользователями |
| 14 | +- **POST /users/setIsActive** - Установка флага активности пользователя |
| 15 | +- **GET /users/getReview?user_id={id}** - Получение списка PR'ов, где пользователь назначен ревьювером |
| 16 | + |
| 17 | +### Управление Pull Request'ами |
| 18 | +- **POST /pullRequest/create** - Создание PR и автоматическое назначение до 2 ревьюверов из команды автора |
| 19 | +- **POST /pullRequest/merge** - Пометка PR как слитого (идемпотентная операция) |
| 20 | +- **POST /pullRequest/reassign** - Переназначение конкретного ревьювера на другого из его команды |
| 21 | + |
| 22 | +### Статистика |
| 23 | +- **GET /statistics** - Получение статистики назначений ревьюверов: |
| 24 | + - Количество назначений по каждому пользователю |
| 25 | + - Количество ревьюверов на каждый PR |
| 26 | + |
| 27 | +## Технологический стек |
| 28 | + |
| 29 | +- **Java 17** - язык программирования |
| 30 | +- **Spring Boot 3.2.5** - фреймворк для разработки веб-приложений |
| 31 | +- **PostgreSQL 15** - реляционная база данных |
| 32 | +- **Liquibase** - управление миграциями базы данных |
| 33 | +- **MapStruct 1.5.5** - генерация мапперов для преобразования объектов |
| 34 | +- **Lombok 1.18.32** - уменьшение boilerplate кода |
| 35 | +- **JUnit 5** - фреймворк для модульного и интеграционного тестирования |
| 36 | +- **Mockito** - библиотека для создания мок-объектов |
| 37 | +- **Testcontainers** - библиотека для интеграционных тестов с реальной базой данных |
| 38 | +- **Maven** - система сборки проекта |
| 39 | +- **Docker & Docker Compose** - контейнеризация и оркестрация |
| 40 | + |
| 41 | +## Архитектура проекта |
| 42 | + |
| 43 | +Проект организован в виде многомодульного Maven-проекта: |
| 44 | + |
| 45 | +``` |
| 46 | +avito-test/ |
| 47 | +├── avito-test-domain/ # Доменные модели, сущности JPA, репозитории |
| 48 | +├── avito-test-db/ # Миграции базы данных (Liquibase) |
| 49 | +├── avito-test-impl/ # Реализация бизнес-логики, контроллеры, сервисы, мапперы |
| 50 | +└── pom.xml # Корневой POM файл |
| 51 | +``` |
| 52 | + |
| 53 | +## Требования |
| 54 | + |
| 55 | +- **Java 17** или выше |
| 56 | +- **Maven 3.6+** |
| 57 | +- **Docker** и **Docker Compose** (для запуска через контейнеры) |
| 58 | +- **PostgreSQL 15** (если запускаете локально без Docker) |
| 59 | + |
| 60 | +## Установка и запуск |
| 61 | + |
| 62 | +### Запуск через Docker Compose (рекомендуется) |
| 63 | + |
| 64 | +1. Клонируйте репозиторий: |
| 65 | +```bash |
| 66 | +git clone <repository-url> |
| 67 | +cd avito-test |
| 68 | +``` |
| 69 | + |
| 70 | +2. Запустите приложение через Docker Compose: |
| 71 | +```bash |
| 72 | +docker-compose up --build |
| 73 | +``` |
| 74 | + |
| 75 | +Приложение будет доступно по адресу: `http://localhost:8080` |
| 76 | + |
| 77 | +### Локальный запуск |
| 78 | + |
| 79 | +1. Убедитесь, что PostgreSQL запущен и доступен: |
| 80 | +```bash |
| 81 | +# Создайте базу данных |
| 82 | +createdb avito_test |
| 83 | + |
| 84 | +# Или используйте Docker для PostgreSQL |
| 85 | +docker run -d \ |
| 86 | + --name avito-test-postgres \ |
| 87 | + -e POSTGRES_DB=avito_test \ |
| 88 | + -e POSTGRES_USER=postgres \ |
| 89 | + -e POSTGRES_PASSWORD=postgres \ |
| 90 | + -p 5432:5432 \ |
| 91 | + postgres:15-alpine |
| 92 | +``` |
| 93 | + |
| 94 | +2. Настройте переменные окружения или отредактируйте `avito-test-impl/src/main/resources/application.yaml`: |
| 95 | +```yaml |
| 96 | +spring: |
| 97 | + datasource: |
| 98 | + url: jdbc:postgresql://localhost:5432/avito_test |
| 99 | + username: postgres |
| 100 | + password: postgres |
| 101 | +``` |
| 102 | +
|
| 103 | +3. Соберите проект: |
| 104 | +```bash |
| 105 | +mvn clean install |
| 106 | +``` |
| 107 | + |
| 108 | +4. Запустите приложение: |
| 109 | +```bash |
| 110 | +cd avito-test-impl |
| 111 | +mvn spring-boot:run |
| 112 | +``` |
| 113 | + |
| 114 | +## API документация |
| 115 | + |
| 116 | +Полная документация API доступна в файле `openapi.yml` в формате OpenAPI 3.0. |
| 117 | + |
| 118 | +## Примеры использования API |
| 119 | + |
| 120 | +### Создание команды |
| 121 | + |
| 122 | +```bash |
| 123 | +curl -X POST http://localhost:8080/team/add \ |
| 124 | + -H "Content-Type: application/json" \ |
| 125 | + -d '{ |
| 126 | + "team_name": "backend", |
| 127 | + "members": [ |
| 128 | + { |
| 129 | + "user_id": "u1", |
| 130 | + "username": "Alice", |
| 131 | + "is_active": true |
| 132 | + }, |
| 133 | + { |
| 134 | + "user_id": "u2", |
| 135 | + "username": "Bob", |
| 136 | + "is_active": true |
| 137 | + } |
| 138 | + ] |
| 139 | + }' |
| 140 | +``` |
| 141 | + |
| 142 | +### Создание Pull Request |
| 143 | + |
| 144 | +```bash |
| 145 | +curl -X POST http://localhost:8080/pullRequest/create \ |
| 146 | + -H "Content-Type: application/json" \ |
| 147 | + -d '{ |
| 148 | + "pull_request_id": "pr-1001", |
| 149 | + "pull_request_name": "Add search", |
| 150 | + "author_id": "u1" |
| 151 | + }' |
| 152 | +``` |
| 153 | + |
| 154 | +### Получение статистики |
| 155 | + |
| 156 | +```bash |
| 157 | +curl -X GET http://localhost:8080/statistics |
| 158 | +``` |
| 159 | + |
| 160 | +## Тестирование |
| 161 | + |
| 162 | +Проект содержит полное покрытие тестами: |
| 163 | + |
| 164 | +### Модульные тесты |
| 165 | +- Тесты сервисов с использованием Mockito |
| 166 | +- Тесты контроллеров с использованием MockMvc |
| 167 | + |
| 168 | +### Интеграционные тесты |
| 169 | +- Тесты с реальной базой данных через Testcontainers |
| 170 | +- Полное покрытие всех API endpoints |
| 171 | + |
| 172 | +Запуск всех тестов: |
| 173 | +```bash |
| 174 | +mvn test |
| 175 | +``` |
| 176 | + |
| 177 | +Запуск только интеграционных тестов: |
| 178 | +```bash |
| 179 | +mvn test -Dtest=*IntegrationTest |
| 180 | +``` |
| 181 | + |
| 182 | +Запуск только модульных тестов: |
| 183 | +```bash |
| 184 | +mvn test -Dtest=*ServiceTest,*ControllerTest |
| 185 | +``` |
| 186 | + |
| 187 | +**Примечание:** Для интеграционных тестов требуется запущенный Docker, так как используется Testcontainers. |
| 188 | + |
| 189 | +## База данных |
| 190 | + |
| 191 | +Схема базы данных управляется через Liquibase. Миграции находятся в модуле `avito-test-db/src/main/resources/db/changelog/`. |
| 192 | + |
| 193 | +### Структура базы данных |
| 194 | + |
| 195 | +- **teams** - таблица команд |
| 196 | +- **users** - таблица пользователей |
| 197 | +- **pull_requests** - таблица Pull Request'ов |
| 198 | +- **pull_request_reviewers** - связь многие-ко-многим между PR и ревьюверами |
| 199 | + |
| 200 | +## Бизнес-логика |
| 201 | + |
| 202 | +### Автоматическое назначение ревьюверов |
| 203 | + |
| 204 | +При создании Pull Request автоматически назначаются до 2 ревьюверов из команды автора: |
| 205 | +- Ревьюверы выбираются случайным образом из активных участников команды |
| 206 | +- Автор PR не может быть назначен ревьювером своего PR |
| 207 | +- Если в команде недостаточно кандидатов, назначается меньшее количество |
| 208 | + |
| 209 | +### Переназначение ревьювера |
| 210 | + |
| 211 | +При переназначении ревьювера: |
| 212 | +- Новый ревьювер выбирается из той же команды, что и старый |
| 213 | +- Новый ревьювер должен быть активным |
| 214 | +- Новый ревьювер не должен быть автором PR |
| 215 | +- Новый ревьювер не должен уже быть назначенным на этот PR |
| 216 | +- Нельзя переназначить ревьювера на PR, который уже слит (status = MERGED) |
| 217 | + |
| 218 | +### Обработка ошибок |
| 219 | + |
| 220 | +Сервис возвращает структурированные ошибки в формате: |
| 221 | +```json |
| 222 | +{ |
| 223 | + "error": { |
| 224 | + "code": "ERROR_CODE", |
| 225 | + "message": "Описание ошибки" |
| 226 | + } |
| 227 | +} |
| 228 | +``` |
| 229 | + |
| 230 | +Коды ошибок: |
| 231 | +- `TEAM_EXISTS` - команда уже существует |
| 232 | +- `PR_EXISTS` - Pull Request с таким ID уже существует |
| 233 | +- `PR_MERGED` - попытка изменить уже слитый PR |
| 234 | +- `NOT_ASSIGNED` - ревьювер не назначен на PR |
| 235 | +- `NO_CANDIDATE` - нет доступных кандидатов для назначения |
| 236 | +- `NOT_FOUND` - ресурс не найден |
| 237 | +- |
| 238 | + |
| 239 | +Это тестовое задание для Авито. Код предоставлен для демонстрации навыков разработки. |
| 240 | + |
| 241 | +## Автор |
| 242 | + |
| 243 | +Iakov Lysenko |
| 244 | + |
0 commit comments