Цель дипломного проекта - разработать фронтенд- и бэкенд-части для сайта-агрегатора с реализацией возможности поиска и бронирования книг в различных библиотеках на выбранную дату. Проект подытожит навыки, которые вы получили в рамках прохождения курса, этот проект вы сможете добавить в свое портфолио разработчика.
Во время выполнения дипломного проекта вы закрепите умения в веб-разработке, разработав следующие элементы веб-сайта:
- пользовательский интерфейс
- публичный API
- API пользователя
- API администратора
- чат консультанта
Убедитесь, что совместимы и корректно работают последние версии фреймворков и библиотек:
- React
- Redux
- React Router
- Node.js
- Nest.js
- PostgreSQL (с TypeORM или Prisma)
- WebSocket
В проекте рекомендуется использовать версии фреймворков и библиотек, актуальные на момент ведения разработки, например, NodeJS не ниже 18.0, React не ниже 18.0, WebPack не ниже 5.0.
- Работа над проектом ведется с использованием системы контроля версий Git с публикацией результатов в публичном репозитории(ях) автора на Github.com.
- Публиковаться в репозиторий должны не только окончательные версии файлов, но и промежуточные результаты с возможным тегированием стадий разработки.
- Возможно опубликование проекта как в едином монорепозитории содержащем код бэкенда и фронтенда, так и в двух отдельных репозиториях. Разбиение кода на большее количество репозиториев (например, с выделением библиотек и модулей) не рекомендуется, т.к. это существенно усложнит работу на стадиях разработки, развёртывания и проверки результатов.
- Допускается использование дополнительных инструментов и модулей, не перечисленных в данном задании, если это необходимо для реализации требуемой функциональности и существенно не усложняет ведение проекта и его дальнейшее развёртывание на открытых платформах.
- Не допускается использование библиотек и инструментов, требующих оплаты или заключения лицензионных договоров при своем использовании в открытых проектах такого масштаба.
- Не допускается использование в проекте дополнительных ресурсов, которые потребуют существенных трудовых и финансовых затрат на их организацию и развёртывание при проверке работоспособности проекта.
- Должна быть максимально использована концепция SPA (single page application), т.е. весь переменный контент на странице (списки пользователей и файлов и т.п.) должен формироваться кодом на JavaScript с использованием библиотеки React. Для получения данных должны использоваться асинхронные api-вызовы к серверу приложения;
- Все страницы приложения должны содержать навигационное меню, формируемое в зависимости от состояния аутентификации пользователя (кнопки «Вход», «Выход» и «Регистрация»).
Последние версии Chrome, Firefox, Opera, Safari.
Реализация адаптивности не обязательно. По желанию можно реализовать адаптацию к мобильным устройствам и планшетам (отдельных макетов для них нет, поэтому адаптацию вы продумываете самостоятельно). Также по желанию можно реализовать «резиновую» вёрстку.
- Реализация защиты от XSS-атак
- Безопасность передачи паролей
В документе приводятся описания разных интерфейсов и типов. Для упрощения описания в этом разделе приводятся общие типы.
type ID = number;- Интерфейс может быть реализован по вашему усмотрению. Время, отводимое на дипломную работу, не предполагает существенных усилий по оформлению приложения. Ознакомьтесь с нашим предложением по интерфейсу по ссылке: Визуальная часть проекта
- По желанию вы можете использовать CSS фреймворки типа
Bootstrap, любойMaterial Designили какой вам интересен (при использовании фреймворка укажите это в README.md файле своего проекта). Главное, чтобы интерфейс приложения был логичным и интуитивно понятным пользователю.
Работа над проектом рассчитана на 1 месяц. Для планирования своего времени рекомендуется разбить блоки работы в равных пропорциях на этот период времени. Вы можете начать как с backend части, и потом перейти в frontend, так и работать по модулям, делая сразу и frontend модуля, и backend.
Отправляйте проект на проверку дипломному руководителю поэтапно, чтобы избежать больших правок и более оперативно получать обратную связь от вашего руководителя.
Мы предлагаем такое деление проекта на этапы и задачи:
1 неделя - модуль «Пользователи»
2 неделя - модуль «Библиотеки»
3 неделя - модули «Аренда книг», «Аутентификация и авторизация»
4 неделя - модуль «Чат техподдержки», оформление документации
5 неделя - получение обратной связи от руководителя, при необходимости доработка проекта с повторной проверкой.
- Не откладывайте надолго начало работы над дипломом. В таком случае у вас останется больше времени на получение рекомендаций от руководителя и доработку диплома.
- Разбейте работу над дипломом на части и выполняйте их поочерёдно. Вы будете успевать учитывать комментарии от руководителя и не терять мотивацию на полпути.
- Опубликуйте все изменения в файлах проекта в публичном(ых) репозитории(ях) на github.com. Убедитесь, что репозитории содержат действительно последние версии со всеми изменениями.
- Попробуйте самостоятельно полностью с нуля развернуть приложение, следуя инструкции, описанной вами в README.md. Убедитесь, что приложение разворачивается успешно и работоспособно, протестируйте основные функции.
- Приложите в личном кабинете ссылки на репозиторий(ии) и развёрнутое приложение либо указание, что приложение может быть развёрнуто вами в течение не более 1 рабочего дня по запросу проверяющего.
- Отправьте дипломную работу на проверку.
- В случае возвращения работы на доработку и устранения замечаний выполните необходимые действия в короткий срок и повторно сдайте работу на проверку. В случае необходимости уточнения и каких-либо вопросов, связанных с результатом проверки, свяжитесь с руководителем вашей дипломной работы.
-
Результаты работы должны быть сданы в виде ссылок на публичный(е) репозиторий(и) с кодом на github.com.
-
В корневой папке репозиториев должны обязательно содержаться файлы README.md с детальным описанием структуры папок и файлов проекта, а также инструкции по его развёртыванию и запуску, достаточно подробные для выполнения специалистом, прошедшим обучение по профессии.
-
В случае использования дополнительных инструментов, которые не изучались в программе профессии, должны быть приложены ссылки на документацию по их установке и использованию.
-
В случае опубликования кода фронтенда и бэкенда в раздельных репозиториях общие инструкции по развёртыванию приложения должны быть описаны в README.md в репозитории с бэкендом, в репозитории с фронтендом должны быть инструкции по сборке и подготовке артефактов фронтенда, которые необходимы для развёртывания.
-
В связи с тем, что профессия Fullstack-разработчика предполагает владение всеми технологиями, используемыми при разработке комплексных приложений с пользовательским интерфейсом, оценке подлежит также удобство пользования приложением. Недостатки, ведущие к существенным трудностям в работе пользователя с приложением могут быть основанием для отправки работы на доработку и устранением замечаний.
Модуль «Пользователи» предназначается для создания, хранения и поиска профилей пользователей.
Модуль «Пользователи» используется функциональными модулями для регистрации и аутентификации.
Данные пользователя должны храниться в БД PostgreSQL.
Модель данных User пользователя должна содержать поля:
| Название | Тип | Обязательное | Уникальное | По умолчанию |
|---|---|---|---|---|
| _id | number |
да | да | |
string |
да | да | ||
| passwordHash | string |
да | нет | |
| name | string |
да | нет | |
| contactPhone | string |
нет | нет | |
| role | string |
да | нет | client |
Модуль «Пользователи» должен быть реализован в виде NestJS-модуля и экспортировать сервисы с интерфейсами:
interface SearchUserParams {
limit: number;
offset: number;
email: string;
name: string;
contactPhone: string;
}
interface IUserService {
create(data: Partial<User>): Promise<User>;
findById(id: ID): Promise<User>;
findByEmail(email: string): Promise<User>;
findAll(params: SearchUserParams): Promise<User[]>;
}Поле role может принимать одно из значений:
client,admin,manager.
При поиске IUserService.findAll() поля email, name и contactPhone должны проверяться на частичное совпадение.
Модуль «Библиотеки» предназначается для хранения и поиска библиотек и их книг.
Модуль «Библиотеки» используется функциональными модулями для показа списка книг для бронирования, а также для их добавления и удаления.
Данные должны храниться в БД PostgreSQL.
Модель данных Library должна содержать поля:
| Название | Тип | Обязательное | Уникальное | По умолчанию |
|---|---|---|---|---|
| id | number |
да | да | autoinc |
| name | string |
да | нет | |
| address | string |
да | нет | |
| description | string |
нет | нет | |
| createdAt | Date |
да | нет | |
| updatedAt | Date |
да | нет |
Модель данных Book должна содержать поля:
| Название | Тип | Обязательное | Уникальное | По умолчанию |
|---|---|---|---|---|
| id | number |
да | да | autoinc |
| libraryId | number |
да | нет | |
| title | string |
да | нет | |
| author | string |
да | нет | |
| year | number |
нет | нет | |
| description | string |
нет | нет | |
| coverImage | string |
нет | нет | |
| isAvailable | boolean |
да | нет | true |
| totalCopies | number |
да | нет | 1 |
| availableCopies | number |
да | нет | 1 |
Модель данных BookRental должна содержать поля:
| Название | Тип | Обязательное | Уникальное | По умолчанию |
|---|---|---|---|---|
| id | number |
да | да | autoinc |
| userId | number |
да | нет | |
| libraryId | number |
да | нет | |
| bookId | number |
да | нет | |
| dateStart | Date |
да | нет | |
| dateEnd | Date |
да | нет | |
| status | string |
да | нет | "reserved" |
type RentalStatus = "reserved" | "active" | "completed" | "cancelled";
interface BookRental {
id: number;
userId: number;
libraryId: number;
bookId: number;
dateStart: Date;
dateEnd: Date;
status: RentalStatus;
createdAt: Date;
updatedAt: Date;
}Модуль «Чат техподдержки» предназначается для хранения обращений в техподдержку и сообщений в чате обращения.
Модуль «Чат техподдержки» используется функциональными модулями для реализации возможности общения пользователей с поддержкой.
Данные чатов должны храниться в БД PostgreSQL.
Модель данных чата SupportRequest должна содержать поля:
| Название | Тип | Обязательное | Уникальное |
|---|---|---|---|
| _id | number |
да | да |
| user | number |
да | нет |
| createdAt | Date |
да | нет |
| messages | Message[] |
нет | нет |
| isActive | bool |
нет | нет |
Модель сообщения Message должна содержать поля:
| Название | Тип | Обязательное | Уникальное |
|---|---|---|---|
| _id | number |
да | да |
| author | number |
да | нет |
| sentAt | Date |
да | нет |
| text | string |
да | нет |
| readAt | Date |
нет | нет |
Сообщение считается прочитанным, когда поле readAt не пустое.
Модуль «Чат техподдержки» должен быть реализован в виде NestJS-модуля и должен экспортировать сервисы с интерфейсами:
interface CreateSupportRequestDto {
user: ID;
text: string;
}
interface SendMessageDto {
author: ID;
supportRequest: ID;
text: string;
}
interface MarkMessagesAsReadDto {
user: ID;
supportRequest: ID;
createdBefore: Date;
}
interface GetChatListParams {
user: ID | null;
isActive: bool;
}
interface ISupportRequestService {
findSupportRequests(params: GetChatListParams): Promise<SupportRequest[]>;
sendMessage(data: SendMessageDto): Promise<Message>;
getMessages(supportRequest: ID): Promise<Message[]>;
subscribe(
handler: (supportRequest: SupportRequest, message: Message) => void,
): () => void;
}
interface ISupportRequestClientService {
createSupportRequest(data: CreateSupportRequestDto): Promise<SupportRequest>;
markMessagesAsRead(params: MarkMessagesAsReadDto);
getUnreadCount(supportRequest: ID): Promise<Message[]>;
}
interface ISupportRequestEmployeeService {
markMessagesAsRead(params: MarkMessagesAsReadDto);
getUnreadCount(supportRequest: ID): Promise<Message[]>;
closeRequest(supportRequest: ID): Promise<void>;
}- Метод
ISupportRequestClientService.getUnreadCountдолжен возвращать количество сообщений, которые были отправлены любым сотрудником поддержки и не отмечены прочитанным. - Метод
ISupportRequestClientService.markMessagesAsReadдолжен выставлять текущую дату в поле readAt всем сообщениям, которые не были прочитаны и были отправлены не пользователем. - Метод
ISupportRequestEmployeeService.getUnreadCountдолжен возвращать количество сообщений, которые были отправлены пользователем и не отмечены прочитанными. - Метод
ISupportRequestEmployeeService.markMessagesAsReadдолжен выставлять текущую дату в поле readAt всем сообщениям, которые не были прочитаны и были отправлены пользователем. - Метод
ISupportRequestEmployeeService.closeRequestдолжен менять флагisActiveнаfalse. - Оповещения должны быть реализованы через механизм
EventEmitter.
GET /api/common/booksQuery-параметры:
- library - ID библиотеки для фильтра
- author - фильтр по автору
- title - фильтр по названию
- availableOnly - только доступные для аренды
GET /api/common/books/:idPOST /api/admin/libraries/Body-параметры:
{
"name": string,
"address": string,
"description": string
}POST /api/admin/books/Multipart/form-data:
- title: string
- author: string
- year: number
- description: string
- libraryId: number
- totalCopies: number
- coverImage: File
[Остальные API endpoints адаптированы аналогично]
POST /api/client/rentalsBody-параметры:
{
"bookId": number,
"libraryId": number,
"dateStart": string,
"dateEnd": string
}Должно быть оформлено в виде отдельного NestJS-модуля.
Модуль «Аутентификация и авторизация» предназначен для:
- управления сессией пользователя,
- регистрации пользователей.
Хранение сессии должно реализовываться посредством библиотеки passport.js с хранением сессии в памяти приложения.
Аутентификация пользователя производится с помощью модуля «Пользователи». Каждому пользователю назначается одна из ролей - клиент, администратор, консультант.
Стартует сессию пользователя и выставляет Cookies.
POST /api/auth/login{
"email": string,
"password": string
}{
"email": string,
"name": string,
"contactPhone": string
}Доступно только не аутентифицированным пользователям.
401- если пользователя с указанным email не существует или пароль неверный.
Завершает сессию пользователя и удаляет Cookies.
POST /api/auth/logoutПустой ответ.
Доступно только аутентифицированным пользователям.
Позволяет создать пользователя с ролью client в системе.
POST /api/client/register{
"email": string,
"password": string,
"name": string,
"contactPhone": string
}{
"id": string,
"email": string,
"name": string
}Доступно только не аутентифицированным пользователям.
400- если email уже занят.
Позволяет пользователю с ролью admin создать пользователя в системе.
POST /api/admin/users/{
"email": string,
"password": string,
"name": string,
"contactPhone": string,
"role": string
}{
"id": string,
"email": string,
"name": string,
"contactPhone": string,
"role": string
}Доступно только пользователям с ролью admin.
401- если пользователь не аутентифицирован;403- если роль пользователя неadmin.
Позволяет пользователю с ролью admin создать пользователя в системе.
GET /api/admin/users/
GET /api/manager/users/- limit - количество записей в ответе;
- offset - сдвиг от начала списка;
- name - фильтр по полю;
- email - фильтр по полю;
- contactPhone - фильтр по полю.
[
{
"id": string,
"email": string,
"name": string,
"contactPhone": string
}
]GET /api/admin/users/Доступно только пользователям с ролью admin.
GET /api/manager/users/Доступно только пользователям с ролью manager.
401- если пользователь не аутентифицирован;403- если роль пользователя не подходит.
Позволяет пользователю с ролью client создать обращение в техподдержку.
POST /api/client/support-requests/{
"text": string
}[
{
"id": string,
"createdAt": string,
"isActive": boolean,
"hasNewMessages": boolean
}
]Доступно только пользователям с ролью client.
401- если пользователь не аутентифицирован;403- если роль пользователя не подходит.
Позволяет пользователю с ролью client получить список обращений для текущего пользователя.
GET /api/client/support-requests/- limit - количество записей в ответе;
- offset - сдвиг от начала списка;
- isActive - фильтр по полю.
[
{
"id": string,
"createdAt": string,
"isActive": boolean,
"hasNewMessages": boolean
}
]Доступно только пользователям с ролью client.
401- если пользователь не аутентифицирован;403- если роль пользователя не подходит.
Позволяет пользователю с ролью manager получить список обращений от клиентов.
GET /api/manager/support-requests/- limit - количество записей в ответе;
- offset - сдвиг от начала списка;
- isActive - фильтр по полю.
[
{
"id": string,
"createdAt": string,
"isActive": boolean,
"hasNewMessages": boolean,
"client": {
"id": string,
"name": string,
"email": string,
"contactPhone": string
}
}
]Доступно только пользователям с ролью manager.
401- если пользователь не аутентифицирован;403- если роль пользователя не подходит.
Позволяет пользователю с ролью manager или client получить все сообщения из чата.
GET /api/common/support-requests/:id/messages[
{
"id": string,
"createdAt": string,
"text": string,
"readAt": string,
"author": {
"id": string,
"name": string
}
}
]Доступно только пользователям с ролью manager и пользователю с ролью client, который создал обращение.
401- если пользователь не аутентифицирован;403- если роль пользователя не подходит.
Позволяет пользователю с ролью manager или client отправлять сообщения в чат.
POST /api/common/support-requests/:id/messages{
"text": string
}[
{
"id": string,
"createdAt": string,
"text": string,
"readAt": string,
"author": {
"id": string,
"name": string
}
}
]Доступно только пользователям с ролью manager и пользователю с ролью client, который создал обращение.
401- если пользователь не аутентифицирован;403- если роль пользователя не подходит.
Позволяет пользователю с ролью manager или client отправлять отметку, что сообщения прочитаны.
POST /api/common/support-requests/:id/messages/read{
"createdBefore": string
}{
"success": true
}Доступно только пользователям с ролью manager и пользователю с ролью client, который создал обращение.
401- если пользователь не аутентифицирован;403- если роль пользователя не подходит.
Позволяет пользователю с ролью manager или client получать новые сообщения в чате через WebSocket.
message: subscribeToChat payload: chatId
{
"id": string,
"createdAt": string,
"text": string,
"readAt": string,
"author": {
"id": string,
"name": string
}
}Доступно только пользователям с ролью manager и пользователю с ролью client, который создал обращение.
Для запуска приложения в корне проекта должны находиться следующие файлы:
package.jsonиpackage-lock.jsonс описанными зависимостями,Dockerfileдля сборки образа приложения,docker-compose.yamlс сервисом приложения и сервисом БДPostgreSQL,README.meс описанием проекта и вариантами его запуска.
Настройка параметров приложения должна производиться через переменные окружения. Это требование как для запуска в окружении хоста, так и при работе с Docker.
Список переменных окружения должен быть описан в файле .env-example. Этот файл не должен содержать значений. Пример файла:
HTTP_HOST=
HTTP_PORT=
POSTGRES_HOST=
POSTGRES_PORT=
POSTGRES_USER=
POSTGRES_PASSWORD=
POSTGRES_DB=Для запуска приложения должен использоваться скрипт npm start, описанный в package.json.