{"id":21175529,"url":"https://github.com/capcom6-learning/netology-ndse-project","last_synced_at":"2025-07-20T01:32:43.648Z","repository":{"id":227895798,"uuid":"767926726","full_name":"capcom6-learning/netology-ndse-project","owner":"capcom6-learning","description":null,"archived":false,"fork":false,"pushed_at":"2024-12-10T06:38:30.000Z","size":1233,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-14T18:29:53.488Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"JavaScript","has_issues":false,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/capcom6-learning.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-03-06T06:34:26.000Z","updated_at":"2024-12-10T06:38:30.000Z","dependencies_parsed_at":"2024-03-15T17:53:53.771Z","dependency_job_id":"0b46b8a4-bdb7-42dd-afdb-5f9f40f4582e","html_url":"https://github.com/capcom6-learning/netology-ndse-project","commit_stats":null,"previous_names":["capcom6/netology-ndse-project","capcom6-learning/netology-ndse-project"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/capcom6-learning/netology-ndse-project","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fnetology-ndse-project","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fnetology-ndse-project/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fnetology-ndse-project/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fnetology-ndse-project/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/capcom6-learning","download_url":"https://codeload.github.com/capcom6-learning/netology-ndse-project/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/capcom6-learning%2Fnetology-ndse-project/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":266053828,"owners_count":23869496,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-20T16:59:48.816Z","updated_at":"2025-07-20T01:32:43.622Z","avatar_url":"https://github.com/capcom6-learning.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Курсовой проект «NDSE: настройка окружения и Express.js»\n\nКурсовой проект представляет собой службу доставки. Ваша задача — создать работающее бэкенд-приложение, всеми основными функциями которого можно пользоваться.\n\n## Быстрый старт\n\nДля быстрого старта можно использовать Docker Compose:\n\n```bash\ndocker-compose up\n```\n\nПри этом будет запущен сервер MongoDB и само приложение на порту 3000.\n\nПримеры запросов приведены в файле [requests.http](./requests.http).\n\n## Цель\nЦель проекта — разработка работающего бэкенд-приложения с API, которое описано в этом документе. \n\nРеализовывать клиент не нужно.\n\n## Содержание\n\n1. Приложение должно содержать следующие **базовые** модули:\n\n- 1.1. Пользователи.\n- 1.2. Объявления.\n- 1.3. Чат.\n\n2. Приложение должно содержать следующие **функциональные** модули:\n\n- 2.1. Регистрация.\n- 2.2. Аутентификация.\n- 2.3. Просмотр объявлений.\n- 2.4. Управление объявлениями.\n- 2.5. Общение.\n\n## 1. Описание базовых модулей\n\nБазовые модули служат для описания бизнес-логики и хранения данных.\n\n### 1.1. Модуль «Пользователи»\n\nМодуль «Пользователи» предназначен для создания, хранения и поиска профилей пользователей.\n\nМодуль «Пользователи» используется функциональными модулями для регистрации и аутентификации.\n\nДанные пользователя должны храниться в MongoDB.\n\nМодель данных `User` пользователя должна содержать следующие поля:\n\n| Название     |    Тип     | Обязательное | Уникальное |\n| ------------ | :--------: | :----------: | :--------: |\n| \\_id         | `ObjectId` |      да      |     да     |\n| email        |  `string`  |      да      |     да     |\n| passwordHash |  `string`  |      да      |    нет     |\n| name         |  `string`  |      да      |    нет     |\n| contactPhone |  `string`  |     нет      |    нет     |\n\n#### 1.1.1. Функция «Создание пользователя»\n\n```js\nconst user = await UserModule.create(data);\n```\n\nАргумент `data` должен соответствовать полям модели `User`, кроме \\_id.\n\nРезультатом работы функции должен быть `Promise`, который резолвится с объектом модели `User`.\n\n#### 1.1.2. Функция «Поиск пользователя по email»\n\n```js\nconst user = await UserModule.findByEmail(email);\n```\n\nАргумент `email` должен быть строкой.\n\nРезультатом работы функции должен быть `Promise`, который резолвится с объектом модели `User` или `null`, если пользователь\nне существует.\n\n### 1.2. Модуль «Объявления»\n\nМодуль «Объявления» предназначается для хранения и поиска объявлений.\n\nМодуль «Объявления» используется функциональными модулями для показа списка объявлений, размещения и удаления\nобъявлений.\n\nДанные объявлений должны храниться в MongoDB.\n\nМодель данных `Advertisement` должна содержать следующие поля:\n\n| Название    |    Тип     | Обязательное | Уникальное |\n| ----------- | :--------: | :----------: | :--------: |\n| \\_id        | `ObjectId` |      да      |     да     |\n| shortText   |  `string`  |      да      |    нет     |\n| description |  `string`  |     нет      |    нет     |\n| images      | `string[]` |     нет      |    нет     |\n| userId      | `ObjectId` |      да      |    нет     |\n| createdAt   |   `Date`   |      да      |    нет     |\n| updatedAt   |   `Date`   |      да      |    нет     |\n| tags        | `string[]` |     нет      |    нет     |\n| isDeleted   | `boolean`  |      да      |    нет     |\n\n#### 1.2.1. Функция «Поиск объявления»\n\n```js\nconst advertisements = await Advertisement.find(params);\n```\n\nВ объекте `params` должны учитываться следующие поля:\n\n- `shortText` — поиск регулярным выражением;\n- `description` — поиск регулярным выражением;\n- `userId` — точное совпадение;\n- `tags` — значение в базе данных должно включать все искомые значения.\n\nПоиск должен игнорировать записи, которые помечены удалёнными `isDeleted = true`.\n\nРезультатом работы функции должен быть `Promise`, который резолвится с массивом объектов модели `Advertisement` или пустым\nмассивом.\n\n#### 1.2.2. Создание объявления\n\n```js\nconst advertisement = await Advertisement.create(data);\n```\n\nАргумент `data` должен соответствовать полям модели `Advertisement`, кроме \\_id.\n\nРезультатом работы функции должен быть `Promise`, который резолвится с объектом модели `Advertisement`.\n\n#### 1.2.3. Удаление объявления\n\n```js\nconst advertisement = await Advertisement.remove(id);\n```\n\nАргумент `id` должен быть типа `string` или `ObjectId`.\n\nФункция поиска не должна удалять запись из базы данных, а только выставлять значение флага `isDeleted = true`.\n\n### 1.3. Модуль «Чат»\n\nМодуль «Чат» предназначается для хранения чатов и сообщений в чате.\n\nМодуль «Чат» используется функциональными модулями для реализации возможности общения пользователей.\n\nДанные чатов должны храниться в MongoDB.\n\nМодель данных чата `Chat` должна содержать следующие поля:\n\n| Название  |           Тип            | Обязательное | Уникальное |\n| --------- | :----------------------: | :----------: | :--------: |\n| \\_id      |        `ObjectId`        |      да      |     да     |\n| users     | [`ObjectId`, `ObjectId`] |      да      |    нет     |\n| createdAt |          `Date`          |      да      |    нет     |\n| messages  |       `Message[]`        |     нет      |    нет     |\n\nМодель сообщения `Message` должна содержать следующие поля:\n\n| Название |    Тип     | Обязательное | Уникальное |\n| -------- | :--------: | :----------: | :--------: |\n| \\_id     | `ObjectId` |      да      |     да     |\n| author   | `ObjectId` |      да      |    нет     |\n| sentAt   |   `Date`   |      да      |    нет     |\n| text     |  `string`  |      да      |    нет     |\n| readAt   |   `Date`   |     нет      |    нет     |\n\nСообщение считается прочитанным, когда поле `readAt` не пустое.\n\n#### 1.3.1. Функция «Получить чат между пользователями»\n\n```js\nconst chat = await Chat.find(users);\n```\n\nАргумент функции `[ObjectId, ObjectId]` — ID пользователей.\n\nРезультатом работы функции должен быть `Promise`, который является объектом модели `Chat` или `null`.\n\n#### 1.3.2. Функция «Отправить сообщение»\n\n```js\nconst message = await Chat.sendMessage(data);\n```\n\nПараметры:\n\n| Название |    Тип     | Обязательное |\n| -------- | :--------: | :----------: |\n| author   | `ObjectId` |      да      |\n| receiver | `ObjectId` |      да      |\n| text     |   string   |      да      |\n\nПри отправке сообщения нужно:\n\n1. Найти чат между `author` и `receiver` по полю `Chat.users`. Если чата нет, то создать его.\n2. Добавить в поле `Chat.messages` новое сообщение `Message`. Поле `sentAt` должно соответствовать текущей дате.\n\nРезультатом работы функции должен быть `Promise`, который резолвится с объектом модели `Message`.\n\n#### 1.3.3. Подписаться на новые сообщения в чате\n\n```js\nChat.subscribe((data) =\u003e {});\n```\n\nФункция `Chat.subscribe` должна принимать функцию обратного вызова.\n\nКаждый раз при добавлении сообщения функция обратного вызова должна вызываться со следующими параметрами:\n\n| Название |    Тип     | Обязательное |\n| -------- | :--------: | :----------: |\n| chatId   | `ObjectId` |      да      |\n| message  | `Message`  |      да      |\n\nОповещения должны быть реализованы через механизм `EventEmitter`.\n\n#### 1.3.4. Функция «Получить историю сообщений чата»\n\n```js\nconst messages = await Chat.getHistory(id);\n```\n\nАргумент функции `ObjectId` — `_id` чата.\n\nРезультатом работы функции должен быть `Promise`, который резолвится с массивом объектов модели `Message`.\n\n## 2. Описание функциональных модулей\n\nФункциональные модули предназначены для реализации функций, доступных конечным пользователям.\n\n### 2.1. Регистрация\n\n`POST /api/signup` — зарегистрироваться.\n\nПароль не должен храниться в чистом виде. Его нужно хешировать перед отправкой в модуль «Пользователи».\n\nФормат данных при отправке — JSON-объект. Пример запроса:\n\n```json\n{\n  \"email\": \"kulagin@netology.ru\",\n  \"password\": \"ad service\",\n  \"name\": \"Alex Kulagin\",\n  \"contactPhone\": \"+7 123 456 78 90\"\n}\n```\n\nВ ответ приходит либо сообщение об ошибке, либо JSON-объект с данными:\n\n```json\n{\n  \"data\": {\n    \"id\": \"507f1f77bcf86cd799439011\",\n    \"email\": \"kulagin@netology.ru\",\n    \"name\": \"Alex Kulagin\",\n    \"contactPhone\": \"+7 123 456 78 90\"\n  },\n  \"status\": \"ok\"\n}\n```\n\n```json\n{\n  \"error\": \"email занят\",\n  \"status\": \"error\"\n}\n```\n\n### 2.2. Аутентификация\n\n`POST /api/signin` — залогиниться.\n\nДля реализации аутентификации пользователя должен использоваться механизм сессий и модуль `Passport.js`.\n\nЕсли пользователь не существует или пароль не совпадает, то нужно выдавать ошибку `Неверный логин или пароль`.\n\nТак как пароль не должен храниться в чистом виде, его нужно хешировать и сравнивать с хешем пароля пользователя из\nмодуля «Пользователи».\n\nФормат данных при отправке — JSON-объект. Пример запроса:\n\n```json\n{\n  \"email\": \"kulagin@netology.ru\",\n  \"password\": \"ad service\"\n}\n```\n\nВ ответ приходит либо сообщение об ошибке, либо JSON-объект с данными:\n\n```json\n{\n  \"data\": {\n    \"id\": \"507f1f77bcf86cd799439011\",\n    \"email\": \"kulagin@netology.ru\",\n    \"name\": \"Alex Kulagin\",\n    \"contantPhone\": \"+7 123 456 78 90\"\n  },\n  \"status\": \"ok\"\n}\n```\n\n```json\n{\n  \"error\": \"Неверный логин или пароль\",\n  \"status\": \"error\"\n}\n```\n\n### 2.3. Просмотр объявлений\n\n`GET /api/advertisements` — получить список объявлений.\n\nЭти данные публичные, поэтому аутентификация не требуется.\n\nВ ответ приходит либо сообщение об ошибке, либо JSON-объект с данными:\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"507f1f77bcf86cd799439012\",\n      \"shortTitle\": \"Продам слона\",\n      \"description\": \"kulagin@netology.ru\",\n      \"images\": [\n        \"/uploads/507f1f77bcf86cd799439011/slon_v_profil.jpg\",\n        \"/uploads/507f1f77bcf86cd799439011/slon_v_fas.jpg\",\n        \"/uploads/507f1f77bcf86cd799439011/slon_hobot.jpg\"\n      ],\n      \"user\": {\n        \"id\": \"507f1f77bcf86cd799439011\",\n        \"name\": \"Alex Kulagin\"\n      },\n      \"createdAt\": \"2020-12-12T10:00:00.000Z\"\n    }\n  ],\n  \"status\": \"ok\"\n}\n```\n\n`GET /api/advertisements/:id` — получить данные объявления.\n\nЭти данные публичные, поэтому аутентификация не требуется.\n\nВ ответ приходит либо сообщение об ошибке, либо JSON-объект с данными:\n\n```json\n{\n  \"data\": {\n    \"id\": \"507f1f77bcf86cd799439012\",\n    \"shortTitle\": \"Продам слона\",\n    \"description\": \"kulagin@netology.ru\",\n    \"images\": [\n      \"/uploads/507f1f77bcf86cd799439011/slon_v_profil.jpg\",\n      \"/uploads/507f1f77bcf86cd799439011/slon_v_fas.jpg\",\n      \"/uploads/507f1f77bcf86cd799439011/slon_hobot.jpg\"\n    ],\n    \"user\": {\n      \"id\": \"507f1f77bcf86cd799439011\",\n      \"name\": \"Alex Kulagin\"\n    },\n    \"createdAt\": \"2020-12-12T10:00:00.000Z\"\n  },\n  \"status\": \"ok\"\n}\n```\n\n### 2.4. Управление объявлениями\n\n`POST /api/advertisements` — создать объявление.\n\nЭти данные приватные и требуют проверки аутентификации.\n\nФормат данных при отправке — `FormData`. Пример запроса:\n\n| Поле        | Тип      |\n| ----------- | -------- |\n| shortTitle  | `string` |\n| description | `string` |\n| images      | File[]   |\n\nОбработка загруженных файлов должна производиться с помощью библиотеки multer.\n\nВ ответ приходит либо сообщение об ошибке, либо JSON-объект с данными:\n\n```json\n{\n  \"data\": [\n    {\n      \"id\": \"507f1f77bcf86cd799439012\",\n      \"shortTitle\": \"Продам слона\",\n      \"description\": \"kulagin@netology.ru\",\n      \"images\": [\n        \"/uploads/507f1f77bcf86cd799439011/slon_v_profil.jpg\",\n        \"/uploads/507f1f77bcf86cd799439011/slon_v_fas.jpg\",\n        \"/uploads/507f1f77bcf86cd799439011/slon_hobot.jpg\"\n      ],\n      \"user\": {\n        \"id\": \"507f1f77bcf86cd799439011\",\n        \"name\": \"Alex Kulagin\"\n      },\n      \"createdAt\": \"2020-12-12T10:00:00.000Z\"\n    }\n  ],\n  \"status\": \"ok\"\n}\n```\n\nЕсли пользователь не аутентифицирован и пытается создать объявление, то в ответ должен получить JSON-объект с ошибкой\nи HTTP-код 401.\n\n`DELETE /api/advertisements/:id` — удалить объявление.\n\nЭти данные приватные и требуют проверки аутентификации.\n\nЕсли пользователь не аутентифицирован и пытается создать объявление, то в ответ должен получить JSON-объект с ошибкой\nи HTTP-код 401.\n\nЕсли пользователь аутентифицирован, но не является автором объявления, то в ответ должен получить JSON-объект с ошибкой\nи HTTP-код 403.\n\n### 2.5. Общение\n\nМодуль «Общение» предназначен для онлайн-общения пользователей.\n\nМодуль должен использовать библиотеку Socket.IO.\n\nДля подписки на обновления в чатах модуль должен использовать функционал «Подписка» модуля «Чат».\n\nСообщения, приходящие в `socket`:\n\n- `getHistory` — получить историю сообщений из чата;\n- `sendMessage` — отправить сообщение пользователю.\n\nСобытия, отправляемые через `socket`:\n\n- `newMessage` — отправлено новое сообщение;\n- `chatHistory` — ответ на событие `getHistory`.\n\n**Событие `getHistory`**\n\nСобытие `getHistory` должно принимать в данных ID собеседника.\n\nПо `id` собеседника и `id` текущего пользователя нужно найти чат через функцию «Получить чат между пользователями». Далее для этого чата нужно получить историю сообщений и отправить её в ответ c событием `chatHistory`.\n\n**Событие `sendMessage`**\n\nСобытие `sendMessage` должно получить следующие данные:\n\n| Поле     | Тип      |\n| -------- | -------- |\n| receiver | `string` |\n| text     | `string` |\n\nПолученные данные должны передаваться в функцию «Отправить сообщение» модуля «Чат». Для поля `author` должен использоваться ID текущего пользователя.\n\n**Событие `newMessage`**\n\nСобытие `newMessage` должно вызываться каждый раз, когда в чат отправляется сообщение.\n\nПри подключении нового клиента должна создаваться подписка на новые сообщения в чате (модуль «Чат»). Полученное сообщение передаётся целиком клиенту.\n\n# Запуск приложения\n\nДля запуска приложения в корне проекта должны находиться следующие файлы:\n\n- `package.json` и `package-lock.json` с описанными зависимостями,\n- `Dockerfile` для сборки образа приложения,\n- `docker-compose.yaml` с сервисом приложения и сервисом MongoDB,\n- `README.md` с описанием проекта и вариантами его запуска.\n\nНастройка параметров приложения должна производиться через переменные окружения. Это требование как для запуска в окружении хоста, так и при работе с Docker.\n\nСписок переменных окружения должен быть описан в файле `.env-example`. Этот файл не должен содержать значений. Пример файла:\n\n```bash\nHTTP_HOST=\nHTTP_PORT=\nMONGO_URL=\n```\n\nДля запуска приложения должен использоваться скрипт `npm start`, описанный в `package.json`.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapcom6-learning%2Fnetology-ndse-project","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcapcom6-learning%2Fnetology-ndse-project","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcapcom6-learning%2Fnetology-ndse-project/lists"}