commit be8818b71ff7c70b68ac1209ae762a3ca0688dbe Author: a-tarazevich Date: Thu Nov 20 17:37:54 2025 +0300 feat: Initial commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d769462 --- /dev/null +++ b/.gitignore @@ -0,0 +1,35 @@ +target/ +!.mvn/wrapper/maven-wrapper.jar +!**/src/main/**/target/ +!**/src/test/**/target/ + +### IntelliJ IDEA ### +.idea +*.iws +*.iml +*.ipr + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ +build/ +!**/src/main/**/build/ +!**/src/test/**/build/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..6c369b2 --- /dev/null +++ b/README.md @@ -0,0 +1,96 @@ +# НТО 2025. II отборочный этап. Командные задания — Backend +## 📖 Предыстория + +В компании S есть возможность бронирования мест в пространствах, предназначенных под общее использование (open-space). На данный момент для бронирования места используются различные способы бронирования, разработанные в каждом офисе индивидуально. +Администрации компании S требуется мобильное приложение, как для рядовых сотрудников, так и для администрации с возможностью просмотра забронированных мест. + +## 📑 Технологический стек + +- Java 17 +- Spring Boot +- H2 +- Liquibase + + +## 🛠️ Техническое задание + +Требуется разработать серверное приложение на Java с использованием Spring Boot, которое работает на основе протокола HTTP и взаимодействует с клиентами благодаря RESTful API. + +Для хранения данных о сотрудниках и их посещениях должна использоваться реляционная база данных (H2). Схема БД должна создаваться liquibase-скриптами. ID-поля всех сущностей, сохраняемых в базе, должны выдаваться на уровне БД. Стратегия генерации ID - автоинкремент (1, 2, 3, 4…) + +Сотрудникам не нужно регистрироваться, все данные в базе должны быть предзаполнены liquibase-скриптами при запуске серверного приложения. Данные для предзаполнения таблиц представлены ниже. + +Картинки для аватаров пользователей не должны храниться в БД. Должны быть сохранены лишь URL-адреса на ресурсы, откуда в последующем мобильное приложение загрузит соответствующее изображение. + +Сервер разрабатывается на основе предоставляемой заготовки проекта. Версии зависимостей и сами зависимости изменяться не должны. + + +## 📂 Правила работы с проектом-заготовкой + +В предоставленном проекте необходимо изучить, но никак не модифицировать, не перемещать и не удалять следующие файлы: +- `pom.xml` +- `application.yml` +- все файлы из `db.changelog` + +Кроме описанных выше файлов, в проекте уже созданы основные классы-сущности и добавлены пустые классы всех слоев. В этих классах необходимо будет написать программный код и добавить аннотации для реализации описанного задания. Наименования классов и прочий код уже написанный в предоставляемом проекте **изменять/удалять не нужно, необходимо их доработать**. Добавлять свои дополнительные классы в проект можно. + +Создание таблиц в БД и предзаполнение их требуемыми данными уже реализовано в заготовке при помощи liquibase. В одной из сущностей добавлены аннотации для реализации связи “один ко многим”, обратите внимание, что в проекте потребуется еще связь данного типа. + + +## 🌐 Где необходимо разместить сервер + +Серверное приложение должно быть разработано и протестировано локально (**не требуется** размещать сервер удаленно и осуществлять его функционирование 24/7). + + +## 📋 Технические требования к серверу и его ответам клиенту + +Для конфигурирования Вашего сервера (его хоста/IP адреса) используйте константы из файла `Constants.kt`. + +| **Тип запроса** | **Путь** | **Описание** | **Параметры/Тело** | **Ответы** | +|-----------------|-----------------------|---------------------------|--------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| +| **GET** | `api//auth` | Проверка авторизации | `` - код для входа | `400` - что-то пошло не так
`401` - кода не существует
`200` - данный код существует - можно пользоваться приложением | +| **GET** | `api//info` | Получение информации о пользователе | `` - код для входа | `400` - что-то пошло не так
`401` - кода не существует
`200` - ОК
{
"name":"Иванов Петр Федорович",
"photoUrl":"",
"booking":{
"2025-01-05": {"id":1,"place":"102"},
"2025-01-06":{"id":2,"place":"209.13"},
"2025-01-09":{"id":3,"place":"Зона 51. 50"}
}
}
| +| **GET** | `api//booking` | Получение доступных для бронирования мест | `` - код для входа | `400` - что-то пошло не так
`401` - кода не существует
`200` - ОК
{
"2025-01-05": [{"id": 1, "place": "102"},{"id": 2, "place": "209.13"}],
"2025-01-06": [{"id": 3, "place": "Зона 51. 50"}],
"2025-01-05":[{"id": 1, "place": "102"},{"id": 2, "place": "209.13"}],
"2025-01-05": [{"id": 2, "place": "209.13"}]
}
**Список дат ограничен текущим + 3 днями** (ответ от сервера содержит 4 дня со свободными местами для каждого) +| **POST** | `api//book` | Создание нового бронирования | `` - код для входа
Тело:
{
“date”: “2025-01-05”,
“placeID”: 1
}
|`400` - что-то пошло не так
`401` - кода не существует
`409` - уже забронировано
`201` - бронирование успешно создано + + +## 📊 Пример данных + +Таблица сотрудников: + +| **id** | **name** | **code** | **photo_url** | +|--------|-----------|---------------------------------|---------------------------------------------------------------------------------------------| +| 1 | Ivanov Ivan | 1111 | https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg | +| 2 | Petrov Petr | 2222 | https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg | +| 3 | Kozlov Oleg | 3333 | https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg | +| 4 | Smirnova Anna | 4444 | https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg | + + +Таблица мест для бронирования: + +| **id** | **place_name** | +|--------|-----------------| +| 1 | K-19 | +| 2 | M-16 | +| 3 | T-1 | + + +Таблица бронирований: + +| **id** | **date** | **place_id** | **employee_id** | +|--------|-----------|--------------|------------------| +| 1 | 2025-11-08 | 1 | 1 | +| 2 | 2025-11-10 | 2 | 2 | + + +# 📝 Решение + +Работу необходимо осуществлять в предоставленном проекте-заготовке (шаблоне). +Когда завершите разработку, создайте пулреквест и запустите workflow в учебной системе. + + +## ✅ Особенности оценивания + +При тестировании сервера на него поочередно отправляются команды, описанные в API и ожидаются определенные корректные ответы. +Сервер и приложение тестируются независимо. + diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000..acde5e1 --- /dev/null +++ b/pom.xml @@ -0,0 +1,65 @@ + + + + + + + 4.0.0 + + org.example + NTO-2025-Backend-Team-Task + 1.0-SNAPSHOT + + + 17 + 17 + UTF-8 + + + + org.springframework.boot + spring-boot-starter-parent + 3.5.5 + + + + + org.projectlombok + lombok + + + org.springframework.boot + spring-boot-starter-web + + + com.h2database + h2 + + + org.springframework.boot + spring-boot-starter-data-jpa + + + org.junit.jupiter + junit-jupiter-engine + test + + + org.springframework.boot + spring-boot-starter-test + test + + + org.liquibase + liquibase-core + + + org.springdoc + springdoc-openapi-starter-webmvc-ui + 2.8.8 + + + + \ No newline at end of file diff --git a/src/main/java/com/example/nto/App.java b/src/main/java/com/example/nto/App.java new file mode 100644 index 0000000..e453f89 --- /dev/null +++ b/src/main/java/com/example/nto/App.java @@ -0,0 +1,12 @@ +package com.example.nto; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public class App { + public static void main(String[] args) { + } +} diff --git a/src/main/java/com/example/nto/controller/BookingController.java b/src/main/java/com/example/nto/controller/BookingController.java new file mode 100644 index 0000000..9885f84 --- /dev/null +++ b/src/main/java/com/example/nto/controller/BookingController.java @@ -0,0 +1,10 @@ +package com.example.nto.controller; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public class BookingController { +} diff --git a/src/main/java/com/example/nto/controller/EmployeeController.java b/src/main/java/com/example/nto/controller/EmployeeController.java new file mode 100644 index 0000000..47658f9 --- /dev/null +++ b/src/main/java/com/example/nto/controller/EmployeeController.java @@ -0,0 +1,10 @@ +package com.example.nto.controller; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public class EmployeeController { +} diff --git a/src/main/java/com/example/nto/entity/Booking.java b/src/main/java/com/example/nto/entity/Booking.java new file mode 100644 index 0000000..21c1981 --- /dev/null +++ b/src/main/java/com/example/nto/entity/Booking.java @@ -0,0 +1,35 @@ +package com.example.nto.entity; + +import jakarta.persistence.FetchType; +import jakarta.persistence.JoinColumn; +import jakarta.persistence.ManyToOne; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.LocalDate; + + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Booking { + + private long id; + + private LocalDate date; + + @ManyToOne(targetEntity = Place.class, fetch = FetchType.LAZY) + @JoinColumn(name = "place_id") + private Place place; + + private Employee employee; +} diff --git a/src/main/java/com/example/nto/entity/Employee.java b/src/main/java/com/example/nto/entity/Employee.java new file mode 100644 index 0000000..a52102b --- /dev/null +++ b/src/main/java/com/example/nto/entity/Employee.java @@ -0,0 +1,34 @@ +package com.example.nto.entity; + +import jakarta.persistence.*; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.List; + + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Employee { + + private long id; + + private String name; + + private String code; + + private String photoUrl; + + @OneToMany(mappedBy = "employee", cascade = CascadeType.ALL, fetch = FetchType.LAZY) + private List bookingList; +} diff --git a/src/main/java/com/example/nto/entity/Place.java b/src/main/java/com/example/nto/entity/Place.java new file mode 100644 index 0000000..00c253b --- /dev/null +++ b/src/main/java/com/example/nto/entity/Place.java @@ -0,0 +1,29 @@ +package com.example.nto.entity; + +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +@Data +@Builder +@NoArgsConstructor +@AllArgsConstructor +public class Place { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private long id; + + private String place; +} diff --git a/src/main/java/com/example/nto/repository/BookingRepository.java b/src/main/java/com/example/nto/repository/BookingRepository.java new file mode 100644 index 0000000..303bb54 --- /dev/null +++ b/src/main/java/com/example/nto/repository/BookingRepository.java @@ -0,0 +1,10 @@ +package com.example.nto.repository; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public interface BookingRepository { +} diff --git a/src/main/java/com/example/nto/repository/EmployeeRepository.java b/src/main/java/com/example/nto/repository/EmployeeRepository.java new file mode 100644 index 0000000..210d29c --- /dev/null +++ b/src/main/java/com/example/nto/repository/EmployeeRepository.java @@ -0,0 +1,10 @@ +package com.example.nto.repository; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public interface EmployeeRepository { +} diff --git a/src/main/java/com/example/nto/repository/PlaceRepository.java b/src/main/java/com/example/nto/repository/PlaceRepository.java new file mode 100644 index 0000000..d3bea1d --- /dev/null +++ b/src/main/java/com/example/nto/repository/PlaceRepository.java @@ -0,0 +1,10 @@ +package com.example.nto.repository; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public interface PlaceRepository { +} diff --git a/src/main/java/com/example/nto/service/BookingService.java b/src/main/java/com/example/nto/service/BookingService.java new file mode 100644 index 0000000..31ec148 --- /dev/null +++ b/src/main/java/com/example/nto/service/BookingService.java @@ -0,0 +1,10 @@ +package com.example.nto.service; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public interface BookingService { +} diff --git a/src/main/java/com/example/nto/service/EmployeeService.java b/src/main/java/com/example/nto/service/EmployeeService.java new file mode 100644 index 0000000..cccd209 --- /dev/null +++ b/src/main/java/com/example/nto/service/EmployeeService.java @@ -0,0 +1,10 @@ +package com.example.nto.service; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public interface EmployeeService { +} diff --git a/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java b/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java new file mode 100644 index 0000000..d24b244 --- /dev/null +++ b/src/main/java/com/example/nto/service/impl/BookingServiceImpl.java @@ -0,0 +1,12 @@ +package com.example.nto.service.impl; + +import com.example.nto.service.BookingService; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public class BookingServiceImpl implements BookingService { +} diff --git a/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java new file mode 100644 index 0000000..f8125e5 --- /dev/null +++ b/src/main/java/com/example/nto/service/impl/EmployeeServiceImpl.java @@ -0,0 +1,12 @@ +package com.example.nto.service.impl; + +import com.example.nto.service.EmployeeService; + +/** + * TODO: ДОРАБОТАТЬ в рамках задания + * ================================= + * МОЖНО: Добавлять методы, аннотации, зависимости + * НЕЛЬЗЯ: Изменять название класса и пакета + */ +public class EmployeeServiceImpl implements EmployeeService { +} diff --git a/src/main/resources/application.yml b/src/main/resources/application.yml new file mode 100644 index 0000000..9d72c0f --- /dev/null +++ b/src/main/resources/application.yml @@ -0,0 +1,26 @@ +# =================================================== +# ВНИМАНИЕ: Этот файл НЕЛЬЗЯ никак модифицировать, +# перемещать и удалять! +# =================================================== +spring: + datasource: + url: jdbc:h2:mem:testdb + + h2: + console: + enabled: true + + jpa: + generate-ddl: false + + hibernate: + ddl-auto: none + + show-sql: true + + liquibase: + enabled: true + change-log: classpath:db.changelog/db.changelog-master.xml + +booking: + days-ahead: 3 \ No newline at end of file diff --git a/src/main/resources/db.changelog/1/0/2025-11-05--0001-employee.xml b/src/main/resources/db.changelog/1/0/2025-11-05--0001-employee.xml new file mode 100644 index 0000000..7f65271 --- /dev/null +++ b/src/main/resources/db.changelog/1/0/2025-11-05--0001-employee.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db.changelog/1/0/2025-11-05--0002-place.xml b/src/main/resources/db.changelog/1/0/2025-11-05--0002-place.xml new file mode 100644 index 0000000..79632fb --- /dev/null +++ b/src/main/resources/db.changelog/1/0/2025-11-05--0002-place.xml @@ -0,0 +1,31 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db.changelog/1/0/2025-11-05--0003-booking.xml b/src/main/resources/db.changelog/1/0/2025-11-05--0003-booking.xml new file mode 100644 index 0000000..9065a1f --- /dev/null +++ b/src/main/resources/db.changelog/1/0/2025-11-05--0003-booking.xml @@ -0,0 +1,40 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db.changelog/data/2025-11-05--0001-employee-data.xml b/src/main/resources/db.changelog/data/2025-11-05--0001-employee-data.xml new file mode 100644 index 0000000..11b50ef --- /dev/null +++ b/src/main/resources/db.changelog/data/2025-11-05--0001-employee-data.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db.changelog/data/2025-11-05--0002-place-data.xml b/src/main/resources/db.changelog/data/2025-11-05--0002-place-data.xml new file mode 100644 index 0000000..fef093b --- /dev/null +++ b/src/main/resources/db.changelog/data/2025-11-05--0002-place-data.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db.changelog/data/2025-11-05--0003-booking-data.xml b/src/main/resources/db.changelog/data/2025-11-05--0003-booking-data.xml new file mode 100644 index 0000000..89f9ae6 --- /dev/null +++ b/src/main/resources/db.changelog/data/2025-11-05--0003-booking-data.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0001-employee-data.csv b/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0001-employee-data.csv new file mode 100644 index 0000000..87ddc6b --- /dev/null +++ b/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0001-employee-data.csv @@ -0,0 +1,5 @@ +name;code;photo_url +Ivanov Ivan;1111;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg +Petrov Petr;2222;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg +Kozlov Oleg;3333;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg +Smirnova Anna;4444;https://catalog-cdn.detmir.st/media/2fe02057f9915e72a378795d32c79ea9.jpeg \ No newline at end of file diff --git a/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0002-place-data.csv b/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0002-place-data.csv new file mode 100644 index 0000000..3354529 --- /dev/null +++ b/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0002-place-data.csv @@ -0,0 +1,4 @@ +place_name +K-19 +M-16 +T-1 \ No newline at end of file diff --git a/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0003-booking-data.csv b/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0003-booking-data.csv new file mode 100644 index 0000000..11f0364 --- /dev/null +++ b/src/main/resources/db.changelog/data/csv/DO_NOT_MODIFY--2025-11-05--0003-booking-data.csv @@ -0,0 +1,3 @@ +date;place_id;employee_id +2025-11-08;1;1 +2025-11-10;2;2 \ No newline at end of file diff --git a/src/main/resources/db.changelog/db.changelog-master.xml b/src/main/resources/db.changelog/db.changelog-master.xml new file mode 100644 index 0000000..390a6dd --- /dev/null +++ b/src/main/resources/db.changelog/db.changelog-master.xml @@ -0,0 +1,18 @@ + + + + + + + + + + + + + + +