├── README.md ├── assets └── course-logo.png ├── cross-check ├── auth-jwt.md ├── ciphering-cli-tool.md ├── docker-basics.md ├── logging-error-handling.md ├── nestjs.md ├── postgresql-typeorm.md ├── rest-service.md ├── simple-crud-api.md ├── testing.md └── typescript-basics.md └── descriptions ├── auth-jwt.md ├── ciphering-cli-tool.md ├── docker-basics.md ├── logging-error-handling.md ├── nestjs.md ├── postgresql-typeorm.md ├── rest-service.md ├── simple-crud-api.md ├── testing.md └── typescript-basics.md /README.md: -------------------------------------------------------------------------------- 1 | # Welcome to the Rolling Scopes School Node.js course! 2 | 3 | ![course logo](./assets/course-logo.png) 4 | 5 | **N.B!**. Tasks for which the field *"Execute in"* written "template" should be implemented using the template, others - in the student's private repository. 6 | 7 | --- 8 | 9 | ## Tasks 10 | 11 | ### Task 1. Ciphering CLI tool 12 | 13 | * Execute in: **private repository** 14 | * [Description](./descriptions/ciphering-cli-tool.md) 15 | * [Cross-check criteria](./cross-check/ciphering-cli-tool.md) 16 | 17 | ### Task 2. Testing 18 | 19 | * Execute in: **private repository (from 1st task)** 20 | * [Description](./descriptions/testing.md) 21 | * [Cross-check criteria](./cross-check/testing.md) 22 | 23 | ### Task 3. Simple CRUD API 24 | 25 | * Execute in: **private repository** 26 | * [Description](./descriptions/simple-crud-api.md) 27 | * [Cross-check criteria](./cross-check/simple-crud-api.md) 28 | 29 | ### Task 4. REST Service 30 | 31 | * Execute in: **template** 32 | * [Description](./descriptions/rest-service.md) 33 | * [Cross-check criteria](./cross-check/rest-service.md) 34 | 35 | ### Task 5. Typescript basics 36 | 37 | * Execute in: **template** 38 | * [Description](./descriptions/typescript-basics.md) 39 | * [Cross-check criteria](./cross-check/typescript-basics.md) 40 | 41 | ### Task 6. Logging & Error Handling 42 | 43 | * Execute in: **template** 44 | * [Description](./descriptions/logging-error-handling.md) 45 | * [Cross-check criteria](./cross-check/logging-error-handling.md) 46 | 47 | ### Task 7. Docker basics 48 | 49 | * Execute in: **template** 50 | * [Description](./descriptions/docker-basics.md) 51 | * [Cross-check criteria](./cross-check/docker-basics.md) 52 | 53 | ### Task 8. PostgreSQL & Typeorm 54 | 55 | * Execute in: **template** 56 | * [Description](./descriptions/postgresql-typeorm.md) 57 | * [Cross-check criteria](./cross-check/postgresql-typeorm.md) 58 | 59 | ### Task 9. Authentication & JWT 60 | 61 | * Execute in: **template** 62 | * [Description](./descriptions/auth-jwt.md) 63 | * [Cross-check criteria](./cross-check/auth-jwt.md) 64 | 65 | ### Task 10. Nest.js 66 | 67 | * Execute in: **template** 68 | * [Description](./descriptions/nestjs.md) 69 | * [Cross-check criteria](./cross-check/nestjs.md) -------------------------------------------------------------------------------- /assets/course-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rolling-scopes-school/basic-nodejs-course/1d0b40fd76b30a13b23d649266d77693ab5bb062/assets/course-logo.png -------------------------------------------------------------------------------- /cross-check/auth-jwt.md: -------------------------------------------------------------------------------- 1 | # Authentication & JWT 2 | 3 | ## NB! Для успешного прохождения тестов обязательно наличие в БД юзера с логином - **admin**, паролем - **admin**. 4 | 5 | ## Базовая реализация 6 | 7 | 1. Пароли пользователей сохраняются в базу в виде хэша с использованием `bcrypt` (либо аналогичного пакета, например, `bcryptjs`). **плюс 20 баллов**. 8 | 2. Добавлен роут `/login`, связанная с ним логика разделена между контроллером и соответствующим сервисом. В случае отсутствия юзера в БД, возвращается **403** (`Forbidden`) HTTP статус. **плюс 20 баллов**. 9 | 3. `JWT` токен содержит `userId` и `login`, секретный ключ хранится в `.env` **плюс 20 баллов**. 10 | 4. Доступ ко всем роутам, за исключением `/login`, `/doc` и `/`, требует аутентификации **плюс 20 баллов**. 11 | 5. Проверка на наличие токена в реквесте реализована в отдельном модуле **на уровне приложения**. В случае если токен не валидный, или отсутствует, возвращается **401** (`Unauthorized`) HTTP статус. **плюс 20 баллов**. 12 | 13 | ## Штрафы: 14 | * Наличие изменений в тестах либо в workflow **минус 100 баллов** 15 | * Внесение изменений в репозиторий после дедлайна не считая коммиты, вносящие изменения только в `Readme.md` **минус 30% от максимального балла за задание (для этого задания 30 баллов)** 16 | * За **каждую** ошибку линтера при запуске `npm run lint` на основе **локального конфига** **минус 20 баллов** (именно `errors`, не `warnings`) 17 | * За **каждую** ошибку компилятора **минус 20 баллов** 18 | * Все тесты `npm run test:auth` должны проходить успешно, каждый не пройденный тест **минус 20 баллов**. 19 | * Имеется явно указанный тип `any` **минус 20 баллов** за каждое использование 20 | * За отсутствие отдельной ветки для разработки **минус 20 баллов** 21 | * За отсутствие `Pull Request` **минус 20 баллов** 22 | * За неполную информацию в описании `Pull Request` (отсутствует либо некорректен один из 3 обязательных пунктов) **минус 10 баллов** 23 | * Меньше 3 коммитов в ветке разработки, не считая коммиты, вносящие изменения только в `Readme.md` — **минус 20 баллов** -------------------------------------------------------------------------------- /cross-check/ciphering-cli-tool.md: -------------------------------------------------------------------------------- 1 | # Ciphering CLI Tool 2 | 3 | **Базовая реализация** 4 | 5 | 1. В `README.md` должно быть описано, как можно запустить программу из командной строки, описаны аргументы, которые можно передать приложению **плюс 10 баллов**. 6 | 2. Если переданы все аргументы и они корректны, приложение читает из файла и записывает в файл преобразованный текст, при этом предыдущие записи не удаляются **плюс 20 баллов** 7 | 3. Приложение работает в соответствии с описанными в задании примерами **плюс 30 баллов** 8 | 4. Если аргументы `input` и/или `output` ведут к несуществующему файлу либо директории,приложение передает соответствующее сообщение в `process.stderr` и прoцесс завершается с кодом, отличным от 0 **плюс 10 баллов** 9 | 5. Если любой из аргументов дублируется, приложение передает соответствующее сообщение в `process.stderr` и прoцесс завершается с кодом, отличным от 0 **плюс 10 баллов** 10 | 6. Если `config` невалиден или отсутствует, приложение передает соответствующее сообщение в `process.stderr` и прoцесс завершается с кодом, отличным от 0 **плюс 20 баллов**. 11 | Объем валидации `config`: 12 | * проверяется, что `config` имеет формат `{XY(-)}n` 13 | * проверяется, что `X` соответствует одному из шифров 14 | * проверяется, что для ROT-8 и Цезаря присутствует элемент `Y` 15 | * проверяется, что для Атбаш отсутствует элемент `Y` 16 | * проверяется, что `Y` — это 1 или 0 17 | 7. Если не передан аргумент с путем до файла на чтение, то чтение осуществляется из `process.stdin` **плюс 10 баллов** 18 | 8. Если не передан аргумент с путем до файла на запись, то вывод осуществляется в `process.stdout` **плюс 10 баллов** 19 | 9. Шифруются/дешифруются только латинские буквы, регистр сохраняется, остальные символы не изменяются **плюс 20 баллов** 20 | 10. Если текст вводится из консоли, то программа не должна завершаться после выполнения шифровки/дешифровки введенного текста, т.е. должна быть возможность ввести еще текст **плюс 10 баллов** 21 | 11. Кодовая база не находится в одном файле, а разделена на файлы в соответствии с выполняемыми задачами (например - функция, преобразующая строку, в отдельном файле, код, создающий transform стрим, в отдельном файле, функция для парсинга и валидации аргументов в отдельном файле и т.п.) **плюс 10 баллов** 22 | 23 | **Продвинутая реализация** 24 | 1. Чтение реализовано при помощи кастомного стрима (класс, отнаследованный от Readable) **плюс 10 баллов** 25 | 2. Запись реализована при помощи кастомного стрима (класс, отнаследованный от Writable) **плюс 10 баллов** 26 | 3. Для передачи сообщения в `process.stderr` используются `пользовательские ошибки` и их обработка **плюс 10 баллов** 27 | 28 | Штрафы: 29 | * Наличие коммитов после дедлайна (за исключением коммитов, изменяющих исключительно `Readme.md` либо вспомогательные файлы (`.gitignore`, `.prettierrc.json` и т.д.) **минус 30% от максимального балла за задание (для этого задания 57 баллов)** 30 | * Использование любых сторонних пакетов, библиотек, фреймворков (за исключением `nodemon`, `prettier` и его плагинов, `eslint` и его плагинов) **минус 150 баллов** 31 | * Запись, чтение, трансформация текста осуществляются без использования потоков (streams) **минус 150 баллов** 32 | * При изменении порядка аргументов происходит ошибка либо изменяется результат выполнения кода **минус 30 баллов** 33 | 34 | N.B. `console.error` пишет ошибку в `process.stderr`. В VS Code, если запустить приложение в режиме [дебага](https://code.visualstudio.com/docs/editor/debugging), можно увидеть в панели output, что цвет сообщений, выводимых в `process.stdout` и `process.stderr` отличаются. 35 | -------------------------------------------------------------------------------- /cross-check/docker-basics.md: -------------------------------------------------------------------------------- 1 | # Docker basics 2 | 3 | ## Базовая реализация: 4 | * Наличие в `Readme.md` секции с инструкцией как запустить приложение **плюс 20 баллов** 5 | * Используется `user-defined bridge` **плюс 30 баллов** 6 | * При возникновении ошибки контейнер должен перезапускается автоматически **плюс 30 баллов** 7 | * Логи и файлы базы данных хранятся в `volumes`, а не в контейнере **плюс 30 баллов** 8 | 9 | ## Продвинутая реализация 10 | * Итоговый docker-образ с приложением имеет размер меньше 300 мб **плюс 20 баллов** 11 | 12 | ## Штрафы: 13 | * Внесение изменений в репозиторий после дедлайна не считая коммиты, вносящие изменения только в `Readme.md` **минус 30% от максимального балла за задание (для этого задания 39 баллов)** 14 | * За отсутствие отдельной ветки для разработки **минус 20 баллов** 15 | * За отсутствие `Pull Request` **минус 20 баллов** 16 | * За неполную информацию в описании `Pull Request` **минус 10 баллов** 17 | * Используется `default bridge network` **минус 20 баллов** 18 | * Конфигурация приложения жестко прописана в` docker-compose.yml` и `Dockerfile` **минус 20 баллов** 19 | * При изменении файлов в папке `src` приложение не перезапускается **минус 20 баллов** 20 | * Должен использоваться специфичный образ. (Например `postgres` и `node`, а не `ubuntu` с установкой `node` или `postgres`) **минус 20 баллов** в случае, если не используется. 21 | * `Postgress image` не указана как зависимость для node `image` **минус 20 баллов** -------------------------------------------------------------------------------- /cross-check/logging-error-handling.md: -------------------------------------------------------------------------------- 1 | # Logging & Error Handling 2 | 3 | ## Базовая реализация 4 | 5 | 1. Логирование (как минимум `url`, `query parameters`, `body`) для всех запросов к серверу, а также кода ответа (`status code`)**плюс 20 баллов** 6 | 2. Добавлена централизованная обработка всех ошибок, которая включает отправку респонса с соответствующим кодом http статуса и их логирование **плюс 20 баллов** 7 | 3. Добавлены обработка и логирование ошибок на событие `uncaughtException` **плюс 10 баллов** 8 | 4. Добавлены обработка и логирование ошибок на событие `unhandledRejection` **плюс 10 баллов** 9 | 5. Процесс логирования осуществляется единственным модулем (т.е. код, осуществляющий логирование, находится в одном модуле, при этом этот модуль может **использоваться** внутри других модулей) **плюс 20 баллов** 10 | 11 | ## Продвинутая реализация 12 | 1. Логи записываются в файл **плюс 20 баллов** 13 | 2. Логи ошибок записываются в отдельный файл (либо только в него, либо в дополнение к записи в общий файл) **плюс 10 баллов** 14 | 3. Добавить переменную окружения для указания уровня логирования и соотвутствующий функционал **плюс 20 баллов** 15 | При указании уровня логирования будут регистрироваться записи этого уровня и всех уровней с более высоким приоритетом. Например, указав уровень 2, вы соберете в лог все сообщения уровней 0, 1 и 2. **Пример** уровней логирования: 16 | * `0`: `error` (ошибка) 17 | * `1`: `warn` (предупреждение) 18 | * `2`: `info` (информация) 19 | * `3`: `debug` (отладочное сообщение) 20 | * `4`: `all` (все сообщения) 21 | 22 | ## Штрафы 23 | * Наличие изменений в тестах либо в workflow **минус 100 баллов** 24 | * Внесение изменений в репозиторий после дедлайна не считая коммиты, вносящие изменения только в `Readme.md` и вспомогательные файлы **минус 30% от максимального балла за задание (для этого задания 39 баллов)** 25 | * За каждый непрошедший тест **минус 10 баллов** 26 | * За **каждую** ошибку линтера при запуске `npm run lint` на основе **локального конфига**, равно как и за ошибки компиляции на основе локального tsconfig **минус 10 баллов** (именно `errors`, не `warnings`) 27 | * Имеется явно указанный тип `any` **минус 20 баллов** за каждое использование 28 | * За отсутствие отдельной ветки для разработки **минус 20 баллов** 29 | * За отсутствие `Pull Request` **минус 20 баллов** 30 | * За неполную информацию в описании `Pull Request` (отсутствует либо некорректен один из 3 обязательных пунктов) **минус 20 баллов** 31 | * Меньше 3 коммитов в ветке разработки, не считая коммиты, вносящие изменения только в `Readme.md`, либо другие вспомогательные файлы — **минус 20 баллов** 32 | 33 | **Подсказки:** 34 | - _(3 пункт)_ Для проверки пропишите `throw Error('Oops!')` ПОСЛЕ `process.on('uncaughtException', () => {...})`. Например, в случае с Express: 35 | ```ts 36 | // Express initialization 37 | const app = express().use(...); 38 | 39 | // Exceptions catcher 40 | process.on('uncaughtException'...); 41 | 42 | // PUT IT HERE 43 | throw Error('Oops!'); 44 | 45 | module.exports = app; 46 | ``` 47 | _Как результат_: вывод в консоли отловленной ошибки 48 | 49 | - _(4 пункт)_ Для проверки пропишите `Promise.reject(Error('Oops!'))` ВНЕ инициализации express и ПОСЛЕ `process.on('unhandledRejection', () => {...})`. Например, в случае с Express: 50 | ```ts 51 | // Express initialization 52 | const app = express().use(...); 53 | 54 | // Exceptions catcher 55 | process.on('unhandledRejection'...); 56 | 57 | // PUT IT HERE 58 | Promise.reject(Error('Oops!')); 59 | 60 | module.exports = app; 61 | ``` 62 | _Как результат_: вывод в консоли отловленной ошибки 63 | -------------------------------------------------------------------------------- /cross-check/nestjs.md: -------------------------------------------------------------------------------- 1 | # NestJS 2 | 3 | Приложение на Nest.js должно работать аналогично ранее созданному. 4 | В файле `Readme.md` должна быть таблица со сравнением производительности `Nestjs express` vs `Nestjs fastify` 5 | 6 | ## Новый функционал 7 | 1. Соответствующий POST-запрос на эндпоинт `/file` позволяет загрузить файл и сохранить его на сервере с приложением **плюс 30 баллов** 8 | 2. GET-запрос на эндпоинт `/file/:filename` позволяет получить загруженный на сервер файл **плюс 30 баллов** 9 | 3. Приходящие со стороны клиента DTO валидируются с использованием `ValidationPipeline` **плюс 30 баллов** 10 | 11 | ## Особенности реализации 12 | 1. `Guards` должны использоваться для работы с авторизацией/аутентификацией **плюс 30 баллов** 13 | 2. В приложении должны использоваться модули для разбиения структуры приложения на различные части (`User`, `Board`, `Task`, `File`) **плюс 30 баллов** 14 | 3. `Exception filters` должны использоваться для обработки исключений в приложении **плюс 30 баллов** 15 | 4. Для работы с базой данных должна использоваться ORM, совместимая с Nest.js (`@nestjs/typeorm`, Prisma, и т.д.) **плюс 30 баллов** 16 | 5. Для логирования должен использоваться встроенный `Logger` или кастомная имплементация **плюс 30 баллов** 17 | 6. Все внешние зависимости для модулей/классов должны предоставляться с помощью механизма `dependency injection` **плюс 30 баллов** 18 | 7. В зависисимости от переменной окружения `USE_FASTIFY` `Nest.js` должен использовать или `express` или `fastify` **плюс 30 баллов** 19 | 8. Необходимо сравнить производительность `Nest.js` с использованием `express` и `fastify` (можно использовать для этих целей [artillery](https://artillery.io/)) **плюс 30 баллов** 20 | 21 | ## Штрафы: 22 | * Наличие изменений в тестах либо в workflow **минус 200 баллов** 23 | * Внесение изменений в репозиторий после дедлайна не считая коммиты, вносящие изменения только в `Readme.md` и другую документацию) **минус 30% от максимального балла за задание (для этого задания 99 баллов)** 24 | * За отсутствие отдельной ветки для разработки **минус 20 баллов** 25 | * За отсутствие `Pull Request` **минус 20 баллов** 26 | * За неполную информацию в описании `Pull Request` (отсутствует либо некорректен один из 3 обязательных пунктов) **минус 10 баллов** 27 | * За **каждую** ошибку линтера при запуске `npm run lint` на основе **локального конфига** **минус 10 баллов** (именно `errors`, не `warnings`) 28 | * За каждый непроходящий тест npm run test:auth **минус 20 баллов** 29 | * Меньше 3 коммитов (не считая коммиты, вносящие изменения только в `Readme.md` и другую документацию) — **минус 20 баллов** 30 | 31 | ## Подсказки 32 | * Для проведения load testing берем один модуль нашего приложения и тестриуем все CRUD методы нашего ресурса (какой ресурс вы будете тестировать вы можете выбрать сами). Если для тестируемого эндпоинта необходима авторизация, то необходимо получить токен заранее и передвать его с каждым запросом. 33 | 34 | Вот пример репорта, полученного с помощью `vegeta`, который вы должны прикрепить в ваш `Readme.md` (инструмент для load tesing может использоваться любой) 35 | 36 | # Express 37 | | | | | 38 | |--------------|----------------------------------|--------------------------------------------------------------------------| 39 | | Requests | [total, rate, throughput] | 65584, 6558.34, 6558.26 | 40 | | Duration | [total, attack, wait] | 10s, 10s, 130.149µs | 41 | | Latencies | [min, mean, 50, 90, 95, 99, max] | 122.225µs, 151.803µs, 147.911µs, 160.265µs, 164.189µs, 194.74µs, 3.094ms | 42 | | Success | [ratio] | 100.00% | 43 | | Status Codes | [code:count] | 200:65584 | 44 | 45 | # Fastify 46 | | | | | 47 | |--------------|----------------------------------|----------------------------------------------------------------------| 48 | | Requests | [total, rate, throughput] | 118489, 11848.94, 11848.84 | 49 | | Duration | [total, attack, wait] | 10s, 10s, 80.298µs | 50 | | Latencies | [min, mean, 50, 90, 95, 99, max] | 63.858µs, 83.763µs, 81.544µs, 88.909µs, 92.922µs, 136.839µs, 8.852ms | 51 | | Success | [ratio] | 100.00% | 52 | | Status Codes | [code:count] | 200:118489 | 53 | -------------------------------------------------------------------------------- /cross-check/postgresql-typeorm.md: -------------------------------------------------------------------------------- 1 | # PostgreSQL & Typeorm 2 | 3 | ## Базовая реализация 4 | 1. В качестве источника данных для `users` используется **PostgreSQL** база данных, работа с которой происходит при помощи `typeorm` **плюс 40 баллов** 5 | 2. В качестве источника данных для `tasks` используется **PostgreSQL** база данных, работа с которой происходит при помощи `typeorm` **плюс 40 баллов** 6 | 3. В качестве источника данных для `boards` используется **PostgreSQL** база данных, работа с которой происходит при помощи `typeorm` **плюс 40 баллов** 7 | 8 | ## Продвинутая реализация 9 | 1. Для создания таблиц с сущностями используются миграции **плюс 50 баллов** 10 | 2. Переменные, используемые для подключения к базе данных, хранятся в `.env` **плюс 10 баллов** 11 | 3. Для установления отношений между сущностями используются соответствующие [декораторы](https://typeorm.io/#/relations) `typeorm` **плюс 10 баллов** 12 | 4. Для проверки задания не требуется локальная установка **PostgreSQL**, подключение осуществляется к базе данных, работающей в `docker` контейнере (на основе созданной в предыдущем задании) **плюс 30 баллов** 13 | 14 | ## Штрафы 15 | * Наличие изменений в тестах либо в workflow **минус 150 баллов** 16 | * Внесение изменений в репозиторий после дедлайна не считая коммиты, вносящие изменения только в `Readme.md` **минус 30% от максимального балла за задание (для этого задания 66 баллов)** 17 | * За **каждую** ошибку линтера при запуске `npm run lint` на основе **локального конфига** **минус 20 баллов** (именно `errors`, не `warnings`) 18 | * За **каждую** ошибку компилятора **минус 20 баллов** 19 | * За каждый непроходящий тест при запуске `npm run test` **минус 20 баллов** 20 | * Имеются явно указанный тип `any` **минус 20 баллов** за каждое использование 21 | * За отсутствие отдельной ветки для разработки **минус 20 баллов** 22 | * За отсутствие `Pull Request` **минус 20 баллов** 23 | * За неполную информацию в описании `Pull Request` (отсутствует либо некорректен один из 3 обязательных пунктов) **минус 10 баллов** 24 | * Меньше 3 коммитов в ветке разработки, не считая коммиты, вносящие изменения только в `Readme.md` **минус 20 баллов** -------------------------------------------------------------------------------- /cross-check/rest-service.md: -------------------------------------------------------------------------------- 1 | # REST service 2 | 3 | Проверку тестов следует проводить в [Node.js 16 LTS версии](https://nodejs.org/en/). 4 | Максимальная оценка за задание **300 баллов** 5 | Минимальная оценка за таску **не может быть меньше 0**. 6 | 7 | # Базовая реализация 8 | 1. Каждый успешный тест при выполнении скрипта `npm run test` **плюс 10 баллов**. 9 | 2. Код приложения, работающий с сущностью `user` разделен по модулям в соответствии с его назначением (к примеру: работа с запросом и ответом в `*.router.js`, бизнес-логика в `*.service.js`, работа с хранилищем данных в `*.repository.js` и т.п.) **плюс 10 баллов** 10 | 4. Аналогично пункту 2 для `boards` **плюс 10 баллов** 11 | 5. Аналогично пункту 2 для `tasks` **плюс 10 баллов** 12 | 13 | # Продвинутая реализация 14 | 1. REST сервис построен на базе фреймворка/библиотеки, отличной от Express и Nest.js, либо на чистом Node.js **плюс 100 баллов** 15 | 16 | ## Штрафы: 17 | * Наличие изменений в тестах либо в workflow **минус 150 баллов** 18 | * Полная ссылка на репозиторий с решением отличается от `https://github.com/%your-gihub-id%/nodejs2021Q4-service` **минус 100 баллов** 19 | * Внесение изменений в репозиторий после дедлайна не считая коммиты, вносящие изменения только в `Readme.md` и другую документацию) **минус 30% от максимального балла за задание (для этого задания 90 баллов)** 20 | * За отсутствие отдельной ветки для разработки **минус 20 баллов** 21 | * За отсутствие `Pull Request` **минус 20 баллов** 22 | * За неполную информацию в описании `Pull Request` (отсутствует либо некорректен один из 3 обязательных пунктов) **минус 20 баллов** 23 | * За **каждую** ошибку линтера при запуске `npm run lint` на основе **локального конфига** (именно `errors`, не `warnings`) **минус 5 баллов** 24 | * Меньше 3 коммитов (не считая коммиты, вносящие изменения только в `Readme.md` и другие вспомогательные файлы) — **минус 20 баллов** 25 | 26 | ## Подсказки: 27 | 28 | > ### **Как увидеть различия для папок `test` и `.github` между текущей веткой и веткой master из темплейта** 29 | > Помимо несовпадения, отображаемого в workflow во время пулл реквеста (`MD5 check`), есть следующий способ: 30 | > 1. Открыть глобальный `.gitconfig`: 31 | > `git config --global -e` 32 | > 2. Добавить в глобальный `.gitconfig` следующие строки. Если вы не используете VSCode замените `code` на соответстующую вашей IDE команду (или путь к выполняемому файлу). 33 | > ``` 34 | > [diff] 35 | > tool = vscode 36 | > [difftool "vscode"] 37 | > cmd = code --wait --diff $LOCAL $REMOTE 38 | > ``` 39 | > 3. Добавить в качестве дополнительного удаленного репозитория темплейт 40 | > ```bash 41 | > git remote add template https://github.com/rolling-scopes-school/nodejs-course-template.git 42 | > ``` 43 | > 4. Создать локальную копию ветки master из темплейта 44 | > `git fetch template master:template-master` 45 | > 5. Запустить сравнение для текущей ветки с веткой master темплейта для тестов 46 | > `git difftool <название текущей ветки> template-master test/` 47 | > 5. Запустить сравнение для текущей ветки с веткой master темплейта для workflow 48 | > `git difftool <название текущей ветки> template-master .github/` -------------------------------------------------------------------------------- /cross-check/simple-crud-api.md: -------------------------------------------------------------------------------- 1 | # In-memory CRUD API 2 | 3 | ## Базовая реализация 4 | 5 | 1. В репозитории с приложением имеется файл `Readme.md`, содержащий подробные инструкции по установке, запуску и использованию приложения **плюс 10 баллов** 6 | 2. Сервер возвращает соответствующие ответы на запросы: 7 | * **GET** `/person`: 8 | * Сервер возвращает статус код 200 и все записи **плюс 6 баллов** 9 | * **GET** `/person/{personId}`: 10 | * Сервер возвращает статус код 200 и запись с `id === personId`, если такая запись есть **плюс 10 баллов** 11 | * Сервер возвращает статус код 400 и соответствующее сообщение, если `personId` невалиден (не `uuid`) **плюс 6 баллов** 12 | * Сервер возвращает статус код 404 и соответствующее сообщение, если запись с `id === personId` не найдена **плюс 6 баллов** 13 | * **POST** `/person` 14 | * Сервер возвращает статус код 201 и свежесозданную запись **плюс 10 баллов** 15 | * Сервер возвращает статус код 400 и соответствующее сообщение, если тело запроса не содержит обязательных полей **плюс 6 баллов** 16 | * **PUT** `/person/{personId}` 17 | * Сервер возвращает статус код 200 и обновленную запись **плюс 10 баллов** 18 | * Сервер возвращает статус код 400 и соответствующее сообщение, если `personId` невалиден (не `uuid`) **плюс 6 баллов** 19 | * Сервер возвращает статус код 404 и соответствующее сообщение, если запись с `id === personId` не найдена **плюс 6 баллов** 20 | * **DELETE** `/person/{personId}` 21 | * Сервер возвращает статус код 204 если запись найдена и удалена **плюс 10 баллов** 22 | * Сервер возвращает статус код 400 и соответствующее сообщение, если `personId` невалиден (не `uuid`) **плюс 6 баллов** 23 | * Сервер возвращает статус код 404 и соответствующее сообщение, если запись с `id === personId` не найдена **плюс 6 баллов** 24 | 25 | ## Продвинутая реализация: 26 | * Ошибки, возникающие при обработке запроса на `/person` корректно обрабатываются и в случае их возникновения API возвращает статус код 500 с соответствующим сообщением **плюс 10 баллов** 27 | * Запросы на несуществующие ресурсы (например, `/some/non/existing/resource`) корректно обрабатываются (возвращается human friendly сообщение и 404 статус код) **плюс 6 баллов** 28 | * Приложение запускается в development-режиме при помощи `nodemon` (имеется `npm` скрипт `start:dev`, который запускает отслеживание изменений в файлах приложения) **плюс 6 баллов** 29 | * Приложение запускается в production-режиме при помощи `webpack` (имеется `npm` скрипт `start:prod`, который запускает процесс сборки webpack и после этого запускает файл с билдом) **плюс 6 баллов** 30 | * Значение `PORT` хранится в `.env` файле **плюс 6 баллов** 31 | 32 | ## Hacker scope 33 | * Имеются E2E тесты, покрывающие логику приложения (не меньше 3 различных сценариев) **плюс 30 баллов** 34 | Пример сценария: 35 | 1. GET-запросом получаем все объекты (ожидается пустой массив) 36 | 2. POST-запросом создается новый объект (ожидается ответ, содержащий свежесозданный объект) 37 | 3. GET-запросом пытаемся получить созданный объект по его `id` (ожидается созданный объект) 38 | 4. PUT-запросом пытаемся обновить созданный объект (ожидается ответ, содержащий обновленный объект с тем же `id`) 39 | 5. DELETE-запросом удаляем созданный объект по `id` (ожидается подтверждение успешного удаления) 40 | 6. GET-запросом пытаемся получить удаленный объект по `id` (ожидается ответ, что такого объекта нет) 41 | 42 | ## Штрафы 43 | * Полная ссылка на репозиторий с решением отличается от `https://github.com/%your-github-id%/simple-crud-api` **минус 100 баллов** 44 | * Использование любых пакетов, библиотек, фреймворков кроме `nodemon`, `dotenv`, `cross-env`, `eslint` и его плагинов, `webpack` и его плагинов, `uuid`, а также библиотек, используемых для тестирования **минус 130 баллов** 45 | * Имеются коммиты после дедлайна, за исключением коммитов, изменяющих исключительно `Readme.md` либо вспомогательные файлы (`.gitignore`, `.prettierrc.json` и т.д.) **минус 30% от максимального балла за задание (минус 49 баллов)** 46 | * Отсутствует PR либо его описание некорректно (отсутствуют либо некорректен любой из 3 обязательных пунктов) **минус 20 баллов** 47 | * Отсутствует отдельная ветка для разработки **минус 20 баллов** 48 | * Меньше 3 коммитов в ветке разработки, не считая коммиты, вносящие изменения только в `Readme.md` либо вспомогательные файлы (`.gitignore`, `.prettierrc.json` и т.д.) **минус 20 баллов** 49 | 50 | -------------------------------------------------------------------------------- /cross-check/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | ## Баллы за реализацию 4 | 5 | 1. По **плюс 2 балла** за каждый юнит-тест (не более **20 баллов** в сумме, баллы начисляются не более чем за 3 теста на каждую отдельную функцию/компонент). 6 | 2. Покрытие не менее 70% **плюс 20 баллов** (покрытие по **строкам**, вычисляется при помощи `jest --coverage`) 7 | 3. В тестах задействованы все сценарии из описания **плюс 20 баллов** 8 | 4. Для тестирования используются mock-объекты **плюс 20 баллов** 9 | 10 | ## Продвинутая реализация 11 | 12 | 1. Покрытие не менее 85% **плюс 20 баллов** (покрытие по **бранчам** вычисляется при помощи `jest --coverage`) 13 | 14 | ## Штрафы 15 | 16 | * Не используется Jest **минус 80 баллов** 17 | * Имеются коммиты после дедлайна, за исключением коммитов, изменяющих исключительно в `Readme.md` либо вспомогательные файлы (`.gitignore`, `.prettierrc.json` и т.д.) **минус 30% от максимального балла за задание (-30 баллов)** 18 | * Отсутствует PR либо его описание некорректно (отсутствуют либо некорректен любой из 3 обязательных пунктов) **минус 20 баллов** 19 | * Отсутствует отдельная ветка для разработки **минус 20 баллов** 20 | * Меньше 3 коммитов в ветке разработки, не считая коммиты, вносящие изменения только в `Readme.md` либо вспомогательные файлы (`.gitignore`, `.prettierrc.json` и т.д.) — **минус 20 баллов** 21 | -------------------------------------------------------------------------------- /cross-check/typescript-basics.md: -------------------------------------------------------------------------------- 1 | # Typescript basics 2 | 3 | ## Оценка миграции (максимум **260 баллов**) 4 | 5 | - За каждый успешно пройденный тест **плюс 10 баллов** (максимум **170 баллов**) 6 | - В проекте настроен ESLint и имеется правило `no-explicit-any` **плюс 20 баллов** 7 | - В проекте имеется `tsconfig` и в нем `noImplicitAny: true` **плюс 20 баллов** 8 | - В проекте имеется `tsconfig` и в нем включена опция [strict](https://www.typescriptlang.org/tsconfig#strict) и при этом strict-related опции не перезаписаны в `false` **плюс 50 баллов** 9 | 10 | ## Оценка TSDoc (максимум **70 баллов**) 11 | 12 | ### Баллы за описание функций при помощи TSDoc 13 | 14 | Расчет количества баллов осуществляется по формуле 15 | X = ( (k1 + k2 + ... + kn) / n) * 70 16 | Где **X** - количество баллов, округленное до целого числа вверх 17 | **n** - общее количество пользовательских функций 18 | **k** - коэффициент выполнения TSDoc-описания для каждой пользовательской функции, где: 19 | * k = 0, если TSDoc-описание полностью неправильное или отсутствует 20 | * k = 0.5, если TSDoc-описание содержит ошибки в части типов или фактического описания работы функции (без учета орфографических, пунктуационных ошибок) 21 | * k = 1, если TSDoc-описание корректно 22 | 23 | 24 | Штрафы: 25 | * Наличие изменений в тестах либо в workflow **минус 150 баллов** 26 | * Внесение изменений в репозиторий после дедлайна не считая коммиты, вносящие изменения только в `Readme.md` и вспомогательные файлы **минус 30% от максимального балла за задание (для этого задания 99 баллов)** 27 | * Не все файлы с кодом в папке src имеют расширение `.ts` **минус 50 баллов** 28 | * За **каждую** ошибку линтера при запуске `npm run lint` на основе **локального конфига** **минус 10 баллов** (именно `errors`, не `warnings`) 29 | * Имеется явно указанный тип `any`, **минус 20 баллов** за каждое использование 30 | * За отсутствие отдельной ветки для разработки **минус 20 баллов** 31 | * За отсутствие `Pull Request` **минус 20 баллов** 32 | * За неполную информацию в описании `Pull Request` (отсутствует либо некорректен один из 3 обязательных пунктов) **минус 20 баллов** 33 | * Меньше 3 коммитов в ветке разработки, не считая коммиты, вносящие изменения только в `Readme.md`, либо другие вспомогательные файлы — **минус 20 баллов** 34 | 35 | Примеры TSDoc-описаний 36 | 37 | Корректное описание 38 | ```ts 39 | /** 40 | * Returns the sum of a and b 41 | * @param a first term number 42 | * @param b second term number 43 | * @returns Sum of a and b number 44 | */ 45 | const sum = (a: number, b: number): number => a + b; 46 | ``` 47 | 48 | Частично корректное описание (отсутствует описание одного из входных параметров) 49 | ```ts 50 | /** 51 | * Returns the sum of a and b 52 | * @param a first term number 53 | * @returns Sum of a and b number 54 | */ 55 | const sum = (a: number, b: number): number => a + b; 56 | ``` 57 | 58 | Некорректное описание (неправильные описание функции и возвращаемого значения, отсутствует описание одного из входных параметров) 59 | ```ts 60 | /** 61 | * Returns the square root from a 62 | * @param a first term number 63 | * @returns string "OK" or "NOT_FOUND" 64 | */ 65 | const sum = (a: number, b: number): number => a + b; 66 | ``` 67 | 68 | ## Подсказки: 69 | 70 | > ### **Как увидеть различия для папок `test` и `.github` между текущей веткой и веткой master из темплейта** 71 | > Помимо несовпадения, отображаемого в workflow во время пулл реквеста (`MD5 check`), есть следующий способ: 72 | > 1. Открыть глобальный `.gitconfig`: 73 | > `git config --global -e` 74 | > 2. Добавить в глобальный `.gitconfig` следующие строки. Если вы не используете VSCode замените `code` на соответстующую вашей IDE команду (или путь к выполняемому файлу). 75 | > ``` 76 | > [diff] 77 | > tool = vscode 78 | > [difftool "vscode"] 79 | > cmd = code --wait --diff $LOCAL $REMOTE 80 | > ``` 81 | > 3. Добавить в качестве дополнительного удаленного репозитория темплейт 82 | > ```bash 83 | > git remote add template https://github.com/rolling-scopes-school/nodejs-course-template.git 84 | > ``` 85 | > 4. Создать локальную копию ветки master из темплейта 86 | > `git fetch template master:template-master` 87 | > 5. Запустить сравнение для текущей ветки с веткой master темплейта для тестов 88 | > `git difftool <название текущей ветки> template-master test/` 89 | > 5. Запустить сравнение для текущей ветки с веткой master темплейта для workflow 90 | > `git difftool <название текущей ветки> template-master .github/` 91 | -------------------------------------------------------------------------------- /descriptions/auth-jwt.md: -------------------------------------------------------------------------------- 1 | # Authentication and JWT 2 | 3 | 1. `POST /users` should accept `password` field and before save replace it with **hash** (use [bcrypt package](https://www.npmjs.com/package/bcrypt) or its equivalent like `bcryptjs`). 4 | 2. Implement `POST /login` method which accepts **JSON** with `login` and `password` and returns **JWT** token in response body: `{ token: }` (use [jsonwebtoken package](https://www.npmjs.com/package/jsonwebtoken)). 5 | 3. **JWT** token should contain `userId` and `login` in a **payload**. 6 | 4. Secret that used for signing the token should be stored in `.env` file. 7 | 5. For all client requests the **JWT** token should be added in HTTP `Authorization` header to all requests that requires authentication. HTTP authentication must follow `Bearer` scheme, e.g.: 8 | ``` 9 | Authorization: Bearer 10 | ``` 11 | 6. Proxy all the requests (except `/login`) and check that HTTP `Authorization` header has the correct value of **JWT** token. 12 | 7. In case of the HTTP `Authorization` header in the request is absent or invalid or doesn’t follow `Bearer` scheme, further router method execution should be stopped and lead to response with HTTP **401** code (Unauthorized error) and the corresponding error message. 13 | 8. **Add admin user to DB** on service start with `login = admin` and `password = admin`. 14 | 15 | ### `bcrypt` installation issues: 16 | 17 | #### If you see an error that starts with: 18 | 19 | ```console 20 | gyp ERR! stack Error: "pre" versions of node cannot be installed, use the --nodedir flag instead 21 | ``` 22 | Please check [compatibility between Node.JS and Bcrypt versions](https://www.npmjs.com/package/bcrypt#version-compatibility). 23 | 24 | #### If you face an error like this: 25 | 26 | ```console 27 | node-pre-gyp ERR! Tried to download(404): https://github.com/kelektiv/node.bcrypt.js/releases/download/v1.0.2/bcrypt_lib-v1.0.2-node-v48-linux-x64.tar.gz 28 | ``` 29 | 30 | Make sure you have the appropriate dependencies installed and configured for your platform. You can find installation instructions for the dependencies for some common platforms in [this page](https://github.com/kelektiv/node.bcrypt.js/wiki/Installation-Instructions). -------------------------------------------------------------------------------- /descriptions/ciphering-cli-tool.md: -------------------------------------------------------------------------------- 1 | # Ciphering CLI Tool 2 | 3 | ## Implement CLI tool that will encode and decode a text by 3 substitution ciphers: 4 | * [Caesar cipher](https://en.wikipedia.org/wiki/Caesar_cipher) 5 | * [Atbash cipher](https://en.wikipedia.org/wiki/Atbash) 6 | * [ROT-8 as variation of ROT-13](https://en.wikipedia.org/wiki/ROT13) 7 | 8 | CLI tool should accept 3 options (short alias and full name): 9 | 10 | 1. **-c, --config**: config for ciphers 11 | Config is a string with pattern `{XY(-)}n`, where: 12 | * `X` is a cipher mark: 13 | * `C` is for Caesar cipher (with shift 1) 14 | * `A` is for Atbash cipher 15 | * `R` is for ROT-8 cipher 16 | * `Y` is flag of encoding or decoding (mandatory for Caesar cipher and ROT-8 cipher and should not be passed Atbash cipher) 17 | * `1` is for encoding 18 | * `0` is for decoding 19 | 2. **-i, --input**: a path to input file 20 | 3. **-o, --output**: a path to output file 21 | 22 | For example, config `"C1-C1-R0-A"` means "encode by Caesar cipher => encode by Caesar cipher => decode by ROT-8 => use Atbash" 23 | 24 | ## Details: 25 | 26 | 1. The task must be solved using only **pure Node.js**. Any libraries and packages (except `nodemon`, `prettier` and its plugins, `eslint` and its plugins) **are prohibited**. 27 | 2. `Config` option is required and should be validated. In case of invalid confing **human-friendly** error should be printed in `stderr` and the process should exit with non-zero status code. 28 | 3. If any option is duplicated (i.e. `bash $ node my_ciphering_cli -c C1-C1-A-R0 -c C0`) then **human-friendly** error should be printed in `stderr` and the process should exit with non-zero status code. 29 | 4. If the input file option is missed - use `stdin` as an input source. 30 | 5. If the output file option is missed - use `stdout` as an output destination. 31 | 6. If the input and/or output file is given but doesn't exist or you can't access it (e.g. because of permissions or it's a directory) - **human-friendly** error should be printed in `stderr` and the process should exit with non-zero status code. 32 | 7. If passed params are fine the output (file or `stdout`) should contain transformed content of input (file or `stdin`). 33 | 8. For encoding/decoding **use only the English alphabet**, all other characters should be kept untouched. 34 | 9. Using `streams` for reading, writing and transformation of text **is mandatory**. 35 | 10. Each cipher is implemented in the form of a **transform stream**. 36 | 11. Streams are piped inside each other according to `config` (you can use `.pipe` streams instances method or `pipeline`) 37 | 38 | **Usage example:** 39 | 40 | ```bash 41 | $ node my_ciphering_cli -c "C1-C1-R0-A" -i "./input.txt" -o "./output.txt" 42 | ``` 43 | 44 | > input.txt 45 | > `This is secret. Message about "_" symbol!` 46 | 47 | > output.txt 48 | > `Myxn xn nbdobm. Tbnnfzb ferlm "_" nhteru!` 49 | 50 | ```bash 51 | $ node my_ciphering_cli -c "C1-C0-A-R1-R0-A-R0-R0-C1-A" -i "./input.txt" -o "./output.txt" 52 | ``` 53 | 54 | > input.txt 55 | > `This is secret. Message about "_" symbol!` 56 | 57 | > output.txt 58 | > `Vhgw gw wkmxkv. Ckwwoik onauv "_" wqcnad!` 59 | 60 | ```bash 61 | $ node my_ciphering_cli -c "A-A-A-R1-R0-R0-R0-C1-C1-A" -i "./input.txt" -o "./output.txt" 62 | ``` 63 | 64 | > input.txt 65 | > `This is secret. Message about "_" symbol!` 66 | 67 | > output.txt 68 | > `Hvwg wg gsqfsh. Asggous opcih "_" gmapcz!` 69 | 70 | ```bash 71 | $ node my_ciphering_cli -c "C1-R1-C0-C0-A-R0-R1-R1-A-C1" -i "./input.txt" -o "./output.txt" 72 | ``` 73 | 74 | > input.txt 75 | > `This is secret. Message about "_" symbol!` 76 | 77 | > output.txt 78 | > `This is secret. Message about "_" symbol!` 79 | -------------------------------------------------------------------------------- /descriptions/docker-basics.md: -------------------------------------------------------------------------------- 1 | # Docker basics 2 | 3 | ## Prerequisites 4 | 5 | 1. Install [Docker](https://docs.docker.com/engine/install/) 6 | 2. Create `Docker Hub` account [Docker Hub](https://hub.docker.com/) 7 | 8 | **Details:** 9 | 10 | 1. Create `.dockerignore` file and list all files that should be ignored by `Docker` 11 | 2. Create `Dockerfile` that will be used for building image of `PostgreSQL` database 12 | 3. Create `Dockerfile` that will be used for building image of your aplication 13 | 4. Create `docker-compose.yml` file that will be used for running multi-container application (your application and `PostgreSQL` database). Specify custom network that will be used for communication between application and database containers 14 | 6. Build images and scan it for security vulnerabilities 15 | 7. Push built images to your private repository on `Docker Hub` 16 | -------------------------------------------------------------------------------- /descriptions/logging-error-handling.md: -------------------------------------------------------------------------------- 1 | # Logging & Error Handling 2 | 3 | Add logging functionality to already existing REST service. 4 | 5 | 1. Add logger which will log incoming requests to service (at least `url`, `query parameters`, `body`) and response `status code`. 6 | 2. Add logger which will log all unhandled `errors` and return a standard message with HTTP code `500` (Internal Server Error). 7 | 3. Add listener and logging to `uncaughtException`. 8 | 4. Add listener and logging to `unhandledRejection`. 9 | 5. Writing to `process.stdout` or to a file both can be used for logging. Any third-party logging library can also be used for this purpose. 10 | 6. Create multiple logging levels and store logging level in environment variable. -------------------------------------------------------------------------------- /descriptions/nestjs.md: -------------------------------------------------------------------------------- 1 | # NestJS 2 | 3 | Your task is to migrate your application to `Nest.js` 4 | 5 | Main application functionality remain unchanged. Besides that, you should implement additional functionalities: 6 | * file uploading functionality (`POST /file`) 7 | * file streaming functionality (`GET /file/:filename`) 8 | * validation of DTO (using Nest.js validation pipelines) 9 | * In `Readme.md` should be table `with Nest.js express` vs `Nest.js fastify` performance comparison. 10 | -------------------------------------------------------------------------------- /descriptions/postgresql-typeorm.md: -------------------------------------------------------------------------------- 1 | # PostgreSQL & Typeorm 2 | 3 | 1. Use **PostgreSQL** database to store **REST** service data (`Users`, `Boards`, `Tasks`) 4 | 2. Use [Typeorm](https://typeorm.io/#/) to store and update data 5 | 3. The information on DB connection should be stored in `.env` file 6 | 4. **PostgeSQL** database should run inside of the `docker` container 7 | -------------------------------------------------------------------------------- /descriptions/rest-service.md: -------------------------------------------------------------------------------- 1 | # REST service 2 | 3 | Let's try to create a competitor for [Trello](https://trello.com/)! 4 | 5 | NB! You must create new repository from [template](https://github.com/rolling-scopes-school/nodejs-course-template/) for this task. Its name must be `nodejs2021Q4-service` i.e. full link to the repository must be `https://github.com/%your-gihub-id%/nodejs2021Q4-service`. 6 | 7 | **Create an application, the application should operate with the following resources:** 8 | 9 | - `User` (with attributes): 10 | ```javascript 11 | { id, name, login, password } 12 | ``` 13 | - `Board` (set of `columns`): 14 | ```javascript 15 | { id, title, columns } 16 | ``` 17 | - `Column` (set of tasks): 18 | ```javascript 19 | { id, title, order } 20 | ``` 21 | - `Task`: 22 | ```javascript 23 | { 24 | id, 25 | title, 26 | order, 27 | description, 28 | userId, //assignee 29 | boardId, 30 | columnId 31 | } 32 | ``` 33 | 34 | **Details:** 35 | 36 | 1. For `User`, `Board` and `Task` REST endpoints with separate router paths should be created 37 | * `User` (`/users` route) 38 | * `GET /users` - get all users (remove password from response) 39 | * `GET /users/:userId` - get the user by id (ex. “/users/123”) (remove password from response) 40 | * `POST /users` - create user 41 | * `PUT /users/:userId` - update user 42 | * `DELETE /users/:userId` - delete user 43 | * `Board` (`/boards` route) 44 | * `GET /boards` - get all boards 45 | * `GET /boards/:boardId` - get the board by id 46 | * `POST /boards` - create board 47 | * `PUT /boards/:boardId` - update board 48 | * `DELETE /boards/:boardId` - delete board 49 | * `Task` (`boards/:boardId/tasks` route) 50 | * `GET boards/:boardId/tasks` - get all tasks 51 | * `GET boards/:boardId/tasks/:taskId` - get the task by id 52 | * `POST boards/:boardId/tasks` - create task 53 | * `PUT boards/:boardId/tasks/:taskId` - update task 54 | * `DELETE boards/:boardId/tasks/:taskId` - delete task 55 | 56 | 2. When somebody `DELETEs` `Board`, all its `Tasks` should be deleted as well. 57 | 58 | 3. When somebody `DELETEs` `User`, all `Tasks` where `User` is assignee should be updated to put `userId = null`. 59 | 60 | 4. For now, these endpoints should operate only with **in-memory** (hardcoded) data, in the next tasks we will use a DB for it. You may organize your modules with the consideration that the data source will be changed soon. 61 | 62 | 5. An `application/json` format should be used for request and response body. 63 | 64 | 6. Do not put everything in one file - use a separate file for application creation (bootstrapping), for controllers (routers) and code related to business logic. Also split files to different modules depends on a domain (user-related, board-related, etc...). 65 | 66 | 7. To run the service `npm start` command should be used. 67 | 68 | 8. Service should listen on PORT `4000`. 69 | 70 | 9. You can try to refactor template using framework that differs from Express.js and Nest.js 71 | 72 | **Hints** 73 | 74 | * To generate all entities `id`s use [uuid](https://www.npmjs.com/package/uuid) package or [Node.js analogue](https://nodejs.org/dist/latest-v16.x/docs/api/crypto.html#cryptorandomuuidoptions). -------------------------------------------------------------------------------- /descriptions/simple-crud-api.md: -------------------------------------------------------------------------------- 1 | # Simple CRUD API 2 | 3 | Your task is to implement simple CRUD API using in-memory database underneath. 4 | NB! You must create new repository for this task. Its name must be `simple-crud-api` i.e. full link to the repository must be `https://github.com/%your-gihub-id%/simple-crud-api`. 5 | 6 | ## Details: 7 | 8 | 1. The task must be solved using only **pure Node.js**. Any libraries and packages (except `nodemon`, `eslint` and its plugins, `prettier` and its plugins, `uuid`, `webpack` and its plugins, testing tools, `dotenv`, `cross-env`) **are prohibited**. 9 | 2. API path `/person`: 10 | * **GET** `/person` or `/person/${personId}` should return all persons or person with corresponding `personId` 11 | * **POST** `/person` is used to create record about new person and store it in database 12 | * **PUT** `/person/${personId}` is used to update record about existing person 13 | * **DELETE** `/person/${personId}` is used to delete record about existing person from database 14 | 3. Persons are stored as `objects` that have following properties: 15 | * `id` — unique identifier (`string`, `uuid`) generated on server side 16 | * `name` — person's name (`string`, **required**) 17 | * `age` — person's age (`number`, **required**) 18 | * `hobbies` — person's hobbies (`array` of `strings` or empty `array`, **required**) 19 | 4. Requests to non-existing endpoints (e.g. `/some-non/existing/resource`) should be handled. 20 | 5. Internal server errors should be handled and processed correctly. 21 | 6. Value of port on which application is running should be stored in `.env` file. 22 | 7. There should be 2 modes of running application: **development** and **production** 23 | 8. There could be some tests for API. 24 | 25 | -------------------------------------------------------------------------------- /descriptions/testing.md: -------------------------------------------------------------------------------- 1 | # Testing 2 | 3 | Write tests for Ciphering machine CLI from 1st task. 4 | For writing tests [Jest](https://jestjs.io/) testing framework should be used. 5 | 6 | You can write simple unit tests on single functions (e.g. ciphering function, arguments parsing function, config validation function, etc.), mock some modules, test CLI using [child processes](https://nodejs.org/dist/latest-v14.x/docs/api/child_process.html) and so on. 7 | 8 | ## Scenarios 9 | 10 | ### Error scenarios 11 | 1) Input: User passes the same cli argument twice; Result: Error message is shown; 12 | e.g. input: `node my_caesar_cli -c C1-C1-A-R0 -c C0` result: `Error: You provided -c argument more than once`; 13 | 2) Input: User doesn't pass -c or --config argument; Result: Error message is shown; 14 | 3) Input: User passes -i argument with path that doesn't exist or with no read access; Result: Error message is shown; 15 | 4) Input: User passes -o argument with path to directory that doesn't exist or with no read access; Result: Error message is shown; 16 | 5) Input: User passes incorrent symbols in argument for --config; Result: Error message is shown; 17 | 18 | ### Success scenarios 19 | 1) Input: User passes correct sequence of symbols as argument for --config that matches regular expression; Result: test passed 20 | 2) Take cipher usage scenarios from [first task description](https://github.com/AlreadyBored/basic-nodejs-course/blob/review-2021Q4/descriptions/caesar-cipher-cli-tool.md) usage examples. -------------------------------------------------------------------------------- /descriptions/typescript-basics.md: -------------------------------------------------------------------------------- 1 | # Typescript basics 2 | 3 | Your task is to migrate your project from Javascript to Typescript 4 | 5 | * All code files in `src` folder must have `.ts` extension 6 | * There shouldn't be errors of TS compiler and linter 7 | * `eslintrc` and `tsconfig` should be used in the project 8 | * Type `any` is not permitted 9 | * Migration to **Typescript** should not break application functionality 10 | * You can also add [TSDoc](https://www.npmjs.com/package/@microsoft/tsdoc) annotations that contain short functionality description as well as description of its arguments (type, description) and its returned value (if applicable) 11 | --------------------------------------------------------------------------------