Next.js setup: Деплой на VPS | Jest | Playwright | CI/CD | Sentry

Ғылым және технология

Мой курс по FSD paromovevg.ru/courses/fsd 🙂
Исходники:
github.com/micro-course/core/...
Волшебный файлик: wonderful-deer-c82.notion.sit...
Мой telegram канал:
t.me/cleanfrontend
Это первое видео я в серии, где я на ваших глазах разработаю продукт с нуля, до заработка первых денег. Особенностью серии будет, что я не буду "срезать углы". Буду использовать FDS архитектуру, тестирование, CI/CD, и все самые актуальные на данный момент инструменты.
Полный стек проекта:
React, Next.js app router, FSD архитектура, postgresql, prisma, zod, @tanstack/react-query, react-hook-form, tailwindcss, shadcn/ui, next-auth, jest , @testing-library/react, playwright
00:00:00 - 0.1 О серии видео
00:01:36 - 0.2 Особенности проекта и меня
00:03:52 - 0.3 Стек проекта
00:08:10 - 0.4 Что будем делать в этом видео
00:11:02 - 1.1 Инициализация проекта
00:23:30 - 1.2 SSH важный ликбез
00:36:02 - 1.3 Загружаем код в репозиторий
00:39:22 - 1.4 Настройка VPS
00:44:56 - 1.5 Настройка пользователя и ssh ключей
00:51:49 - 1.6 Запускаем Next.js на сервере
00:58:37 - 1.7 Запускаем Next.js через pm2 в фоне
01:01:41 - 1.8 Настраиваем фаервол
01:03:38 - 1.9 Настраиваем nginx
01:10:47 - 1.10 Настраиваем https
01:15:21 - 2.1 Добавляем prisma в проект
01:25:25 - 2.2 Делаем пример работы с базой на fsd
02:04:16 - 2.3 Как будем работать с .env
02:07:17 - 2.4 Настраиваем staging для работы с базой
02:13:42 - 3.1 Добавляем jest в проект
02:21:59 - 3.2 Добавляем playwright в проект
02:31:40 - 4.1 CI: Добавляем запуск jest eslint на PR
02:42:23 - 4.2 CD: Настраиваем deploy на пуш в main
03:07:11 - 4.3 CI: Запускаем plawright после деплоя в staging
03:13:53 - 5 Настраиваем production
03:34:48 - 6 Настройка sentry
03:55:29 - 7 Путь фичи

Пікірлер: 96

  • @paromovevg
    @paromovevg4 ай бұрын

    Если вам понравился хостинг, переходите по этой ссылке, мне бонусики будут капать, и вам тоже) timeweb.cloud/r/paromovevg

  • @MegaMaxxon
    @MegaMaxxon5 ай бұрын

    Вау, если прям со всей инфраструктурой, настройкой ci/cd, базой, тестами, nginx и вот это все то это мега круто 👍

  • @kh4ff
    @kh4ffКүн бұрын

    Жаль, что раньше не нашёл твой канал. Таких туториалов практически нет на ютубе. Теперь мне хотябы ясно, куда копать, какие технологии изучать, чтобы правильно деплоить на vps.

  • @vladimirbavtenko9080
    @vladimirbavtenko90805 ай бұрын

    Я в начале видео, но уже хочу все это как минимум повторить на своем проекте и надеюсь, что все будет подробно. Это уникальный контент по реальной разработке и вообще Евгению огромная благодарность за естественную и не занудную подачу материала, тут конечно и голос, и меняющаяся интонация, и свой личный подход с высоты опыта - просто огонь! Я много чего смотрел и смотрю по разработке, но Евгений - уникальный и то, что он делает тоже никто ранее так не делал, да и не сможет из-за особенностей личности в хорошем смысле. Для меня - это топ канал. Желаю и, сам этого очень хочу, чтобы качество контента никогда не падало, с нетерпением жду уже продолжения.

  • @dmitrysvetlov6001
    @dmitrysvetlov60013 ай бұрын

    Канал находка, такого контента даже в en сегменте не видел. потрясающая подача, отличный разбор смежных тем. Каналу удачи.

  • @grol5555
    @grol55552 ай бұрын

    Очень понравилась схема, деплоя, простая и понятная, как раз для pet-проектов. А то начинаешь смотреть видео как всё контеризируют, затем docker-compose и уже остаётся один шаг до kubernetes. Убиваешь уйму времени именно в DevOps для достаточно простого pet-проекта. А в этом видео всё просто, хорошее видео.

  • @abvgd12357
    @abvgd123575 ай бұрын

    Замечательный контент! Приятно узнавать не затертую до дыр инфу, а что то полезное из так называемой "реальной разработки". Лайк и подписка однозначно!

  • @leshamaybe
    @leshamaybe5 ай бұрын

    Твой канал кладезь полезного. За разжевывание деплоя большое спасибо!

  • @krasovsky1
    @krasovsky15 ай бұрын

    Супер контент! И без воды. Огромное спасибо👍

  • @user-mi1hq1dz2b
    @user-mi1hq1dz2bАй бұрын

    Спасибо, Евгений! Очень качественное видео. На просторах ютуба и гугла такго вообще нет. Так еще и файлик создал, который очень помогает мне. Эта база мне очень пригодилась на работе.

  • @Zer0IsNotJustNumber
    @Zer0IsNotJustNumber5 ай бұрын

    не успел посмотреть, уже лайк просто потому что знаю что это того стоит!

  • @DoSmth
    @DoSmth5 ай бұрын

    Привет! Было бы супер увидеть подключение оплаты! Очень мало инфв об этом в ру сегменте, спасибо)

  • @Arman-kp8jf
    @Arman-kp8jf5 ай бұрын

    Очень хороший выбор контента. Удачи!!!

  • @Kinslayer696
    @Kinslayer6965 ай бұрын

    Видео огонь! Могу представить сколько потребовалось времени и сил чтобы все это отснять и смонтировать. Спасибо большое👍

  • @GAccountMe
    @GAccountMe5 ай бұрын

    Начал смотреть, похоже на что-то очень годное! Спасибо=)) Когда продолжение?=)

  • @YakubAx
    @YakubAx5 ай бұрын

    Супер видео ждем продолжение 🔥

  • @ell1ar
    @ell1ar5 ай бұрын

    29:22, Евгений, мне кажется здесь важная неточность (я могу ошибаться, поправьте): Клиент отправляет серверу просто pub ключ, сервер проверяет в списке, есть ли такой ключ (~/.ssh/authorized_keys) и если да, то он с помощью него шифрует случайную строку, отсылает в зашифрованном виде клиенту. Клиент, с помощью секретного ключа, расшифровывает сообщение и отправляет назад серверу. Сервер проверяет, что если расшифрованное клиентом сообщение совпадает с его первоначальным, то вход успешен. Потому что pub ключик, по сути, просто "замок", которым можно закрыть "ящичек". Ничего этот ключ не расшифровывает. А по вашей логике получается наоборот :)

  • @user-vk4si1oz7w
    @user-vk4si1oz7w5 ай бұрын

    Ну до чего приятный паренек! Прям богом дано про чтото рассказыаать, и здорово что выбрал программирование)) лайк, подписка, хоть я и на вью пишу))

  • @pavelsmirnov9818
    @pavelsmirnov98185 ай бұрын

    Крутой контент, большое спасибо

  • @user-lb9oq9up1u
    @user-lb9oq9up1u5 ай бұрын

    Дружище только не бросай прошу! я хочу делать этот проект вместе с тобой

  • @maxblock5233
    @maxblock52335 ай бұрын

    Очень вовремя, круто, спасибо большое

  • @user-df2hp7zm8q
    @user-df2hp7zm8q3 ай бұрын

    Спасибо Евгений. Это наикрутейшее видео. Продолжу дальше смотреть твои видео.

  • @user-hg3oi4qw2d
    @user-hg3oi4qw2d5 ай бұрын

    Круто, это очень круто!!!! Ждем продолжения, очень очень!!!!

  • @sardorsultanov3409
    @sardorsultanov34095 ай бұрын

    Я только начал изучать ci/cd а ваш видео просто топ по понятности

  • @WorldworkMay
    @WorldworkMayАй бұрын

    Шикарный контент! Спасибо!

  • @user-zh6fh6lj8j
    @user-zh6fh6lj8j8 күн бұрын

    Топовый контент, очень сильно помог!

  • @ringnull
    @ringnull4 ай бұрын

    Серьёзно ты подошел к вопросу. То что надо.

  • @user-hg3oi4qw2d
    @user-hg3oi4qw2d4 ай бұрын

    Очень круто! Продолжение ждем...

  • @archee7309
    @archee73094 ай бұрын

    А когда вторая часть? С нетерпением жду продолжения, твои уроки на вес золота

  • @paromovevg

    @paromovevg

    4 ай бұрын

    Уже на канале)

  • @martcarrefour
    @martcarrefour5 ай бұрын

    Очень крутое видео! Не подскажете, когда ждать продолжения?

  • @user-wh9mc2po7g
    @user-wh9mc2po7g5 ай бұрын

    Топ контент, будем смотреть/учиться

  • @artemvictorovich6731
    @artemvictorovich67314 ай бұрын

    Привет! Спасибо за видео! Подскажи, пожалуйста, какой микрофон используешь ?

  • @narwhal6422
    @narwhal64223 ай бұрын

    Неожиданно топ контент😮

  • @vadikcvirko179
    @vadikcvirko1795 ай бұрын

    Давай вторую часть, я поставил лайк и подписался.

  • @narwhal6422
    @narwhal64223 ай бұрын

    Ура я сделал это, правда у меня это заняло часов 25🎉

  • @user-lb9oq9up1u
    @user-lb9oq9up1u3 ай бұрын

    Объясни пожалуйста как ты конфигурационные файлы удалил, перед тем как свой создал?

  • @GAccountMe
    @GAccountMe5 ай бұрын

    Я только разбираюсь с next и fsd, по этому могу заблуждаться. Но мне кажется, что серверные экшены нужно все же хранить отдельно, как отдельный слой абстракции. Ты абстрагировал работу с БД в архитектурный слой репозитория - это прекрасно, я тоже так делаю, но тут же принес этот слой в tsx файл, где у нас ui слой, что, как по мне - плохо, следующий шаг - это писать slq в компонентах=)). Например я стараюсь вынести из компонентов всю бизнеслогинку как раз таки в серверные экшены, а в компонентах оставлять только то, что касается ui и обработки событий, к тому же, в моих кейсах серверные экшены переиспользуются и они довольно объемные по коду, потому что, зачастую содержат много проверок и последовательной логики, что-то по типу - существует ли пользователь, создал ли этот пользователь курс, который хочет удалить - ну и т.д. Если это лежит отдельно это и тестируется лучше. Ну и конечно, я бы все же создал entity для курса и экшен по удалению курса был бы там, а фича бы его дергала, ну ты говоришь что осознанно сделал не так=) Так же вопрос - почему create-course-form лежит в фиче course-list, название явно же говорит что это фича про листинг, мне кажется что нужна фича по типу create-course, ну или все же создать entity для курса и положить эту форму там - вроде это не противоречит fsd, хотя все же эта функциональность явно фича. Еще по типам, ты говорил, что делаешь типы отдельно от тех, что генерит призма - тоже так делаю, но я наследуюсь от типа сущности который дает призма и проста пикаю нужные поля, это все же дает какую-то связь сущностей с базы и типов в приложении, например если в базе поменяется поле name на username, то тайпскрипт скажет что поля name нет в моем типе для приложения. Видос крутой, спасибо! Практически все авторы на ютубе, юдеми и других площадках делают, по принципу - работает и хорошо, очень мало материала по архитектуре, очень не хватает такого контента

  • @paromovevg

    @paromovevg

    5 ай бұрын

    По факту тут не очень показательный пример, так как приложение маленькое и это посути был тестовый пример. - По поводу наследования от типа базы данных, советую посмотреть в сторону чистой архитектуры. Там база и её структура - есть следствие бизнес логики а не наоборот. Если база поменятся, то поменяется только код, который будет адаптировать структуру базы к бизнес сущности, не придётся менять весь остальной код приложения - По поводу экшонов в компонентах. Компонент и так серверный, исполняется на сервере. Я сказал важный момент. Экшон это контроллер, а значит в нём вообще ничего почти не будет. Весь реальный код будет в других модулях. Но просто этот пример был сшилком простым, что бы это делать (Но в следующем видео, я всё равно полностью эшконы вынес в отдельный файл) - По поводу фич и сущностей. Я говорил, что это немного изменённая моя версия fsd. Она решает вопрос слишком большого coupling. Подробнее тоже будет в следющем видео

  • @ringnull
    @ringnull4 ай бұрын

    Когда следующий видос ждать?

  • @front_interviews
    @front_interviews5 ай бұрын

    Благодарю =)

  • @neotom8653
    @neotom86535 ай бұрын

    Очень качественно

  • @goldovyidozhdik3430
    @goldovyidozhdik34304 ай бұрын

    Евгений такой вопрос, а если мне надо будет сделать сайт юр лицу по похожему алгоритму действий, как потом передать его в собственность заказчику? Домен и сервер наверное можно легко переоформить, а с гитхабом непонятно. Может сразу сделать гитхаб и сервер на имя заказчика а самому просто получить доступ? но звучит не надёжно или заказчик просто скачивает файлы с моего репозитория и делает с ними что хочет, а я свой удаляю?

  • @nainkanal3979
    @nainkanal39795 ай бұрын

    Очень крутой стек! Евгений, как часто будут выходить видео с этим курсом?

  • @paromovevg

    @paromovevg

    5 ай бұрын

    Ближайшее время только такие видео и будут выходить. Где то раз в 1.5 - 2 недели

  • @darktmdarkness6952
    @darktmdarkness69524 ай бұрын

    по поводу настройки сервера, есть небольшое замечание: еще для повышения безопасности меняют порт подключения к ssh с 22 на какой-нибудь 22202, и врубают фаервол и блочат все порты кроме ssh, http, https. Что дополнительно повышает устойчивость сервера к взлому.

  • @kirill_prog
    @kirill_prog4 ай бұрын

    Как же это круто! Прошу не останавливайся! Сделай бусти для донатов.

  • @paromovevg

    @paromovevg

    4 ай бұрын

    Сделал) boosty.to/paromov_evg/donate

  • @user-sh3dt6dy8p
    @user-sh3dt6dy8p5 ай бұрын

    если использовать ufw вместе с doker, то внешние порты для докера не блокируются (вроде), надо дополнительно шаманить

  • @alexdenuke
    @alexdenuke3 ай бұрын

    Автору спасибо, но было упущено про то, что линю надо обновить глобально

  • @egrpavlov2694
    @egrpavlov26942 ай бұрын

    В видео немного перепутан алгоритм key-аутентификация. С помощью приватного ключа данные расшифровываются, а публичным шифруются

  • @katada
    @katada5 ай бұрын

    Круто!

  • @1982RUFF
    @1982RUFF5 ай бұрын

    Евгений, спасибо за отличное видео! Очень полезно и информация очень важная... Есть вопрос по поводу VDS сервера - какие должны быть требования под next с размещением небольшого и-магазина? Я взял на нетангелах 4 ядра и 4гб NVMе диск на 10гб - но после деплоя постоянные глюки и pm2 вылетает постоянно.. (( а если брать больше сервер - стоимость возрастает прилично... спасибо заранее за ответ!

  • @paromovevg

    @paromovevg

    5 ай бұрын

    Тут нужно смотреть за мониторами, что не так. Может нагрузка большая и тут уже ничего не сделаешь придётся увеличивать машину, а может просто где то утечка памяти и он периодически отваливается

  • @1982RUFF

    @1982RUFF

    3 ай бұрын

    Ну вроде как проблема была в хостинге... в последнее время что то меняю на сайте и билдю повторно - вроде как работает нормально и не виснет как раньше было) @@maks2

  • @imthebest8000
    @imthebest8000Ай бұрын

    хм, а стоит добавлять docker? Или это уже лишнее?

  • @lepreclown2180
    @lepreclown21805 ай бұрын

    Подскажите пожалуйста, я ведь правильно понял, что используем prisma, локальную БД и напрямую к ней конектимся, только потому что нет отдельного backend. То есть если бы у нас был в реальном проекте backend(python) к примеру, то мы бы просто по API запросы делали?

  • @paromovevg

    @paromovevg

    5 ай бұрын

    В более типичных проектах, да запросы просто шли бы к бекенду. Но тут всё же дальше будет больше отличий. Так как из за fullstack природы этого приложения, будет достаточно много бизнес логики, которую мы будем менеджить

  • @alhongelios53
    @alhongelios533 ай бұрын

    небольшое уточнение по pm2 если прописать просто npx pm2 startup то при перезапуске сервака pm2 не стартует надо указывать еще название ОС то есть писать npx pm2 startup ubuntu

  • @user-yl5kn9gq4p
    @user-yl5kn9gq4pАй бұрын

    Привет молодец продолжай в том же духе😎

  • @user-xs2dx2mh3f
    @user-xs2dx2mh3f4 ай бұрын

    Крутейшее видео, спасибо. Очень ждал подобное. Вопрос по поводу базы: в чём основная мотивация заказа отдельной базы (не развёртывание внутри виртуального сервера)? Ведь за неё нужно платить отдельно. Это связано именно с удобной реализацией бэкапов? Или есть ещё какие-то существенные причины, может это более безопаснее и т.д?

  • @darktmdarkness6952

    @darktmdarkness6952

    4 ай бұрын

    1. настройки. Если вы покупаете вот такую базу у сервиса, она уже минимально настроена под железо и ресурсы сервера и вам ничего делать не нужно. Максимум, добавить в конфиг, какие-то свои настройки специфичные для вашего продукта и приложения. Если вы ставите базу просто рядом, то все настройки должны выполнять сами. И если с мускулом это проблема минимальна, то постгру придется настраивать под ресурсы которые прокинуты, например, в тот же докер, под железо и т.д. 2. up-time. В случае покупки у сервиса сервера бд, в стоимость входит администрирование и поддержка работы базы, самим хостером. Т.е. следить за базой и её безопасностью, нужно им. Если вы ставите рядом, то делать это нужно вам. Например, в случае постгры, собирать логи и метрики, смотреть за наполнением виртуальных таблиц и выполнением auto-vacuum. Если данные в auto-vacuum застряли, самому его выполнять и т.д. 3. производительность. Ваш сервис, это не всегда полтора пользователя в сутки, и может иметь высокую нагрузку на базу, как на запись, так и на чтение, требовать репликации и настройки кластеров, репликаций, регионнальности и много чего еще. Тогда тоже предпочтительнее базу выносить на отдельный сервер. И в не сложных случаях, так же проще скинуть все это на сервис, взяв у них услугу, чем нанимать команду девопсов и датабейз инженеров, или самому во всем этом разбираться.

  • @user-xs2dx2mh3f

    @user-xs2dx2mh3f

    4 ай бұрын

    @@darktmdarkness6952 спасибо за развёрнутый ответ. Очень интересно

  • @igor5379
    @igor53795 ай бұрын

    никто из хитхаба секреты не сможет достать, КРОМЕ самого гидхаб)))

  • @CJIu3eHb
    @CJIu3eHb5 ай бұрын

    Тоже не получилось с фингерпринтом у appleboy/ssh-action, уж и по их мануалу получал отпечаток - глухо. Но оставил без отпечатка пока, т.к. неизвестно, что хуже в таком тонком деле, как безопасность - широко известный пакет с поломанным отпечатком или какой-то малораспространенный D3rHase/ssh-command-action с отпечатком. Кстати, пошарился чуть по другим ssh action - так далеко не у всех проверка отпечатков есть.

  • @Selieznov
    @Selieznov5 ай бұрын

    Не дума делать не только миграцию бд, а и самому?)

  • @Mikalai-yc7yy
    @Mikalai-yc7yy5 ай бұрын

    🔥🔥🔥🔥🔥🔥

  • @plexterq3
    @plexterq35 ай бұрын

    Не пробовали использовать next-safe-action? Она позволит не писать код для валидации, просто передавая в action схему zod. Также там встроен враппер для обработки ошибок. И мы, написав свой слой ошибок, например ActionError, сможем в экшенах только этот тип ошибок передавать на клиент для toast. Ну и также позволит, например писать свой action, например authAction и тогда не надо будет в каждом action проверять авторизацию где она нужна. А ну и также генерит useAction, который как в react-query имеет onSuccuess, onError итд

  • @JJohnson-fy9uz
    @JJohnson-fy9uz3 ай бұрын

    А почему pm2, а не докер?

  • @abdurahmonvahobov8684
    @abdurahmonvahobov86845 ай бұрын

    👍

  • @kixxgopro
    @kixxgopro6 күн бұрын

    топ

  • @grigodoes
    @grigodoes5 ай бұрын

    Крайне полезная информация) спасибо Если создашь boosty с меня моментальная подписка!)

  • @r0mm4k
    @r0mm4k5 ай бұрын

    Привет. Как на счет того, чтобы в докер все это завернуть?

  • @paromovevg

    @paromovevg

    5 ай бұрын

    Вообще хочется эту тему немного оттянуть. Next.js Плохо в докер заворачивается, так как для сборки нужно подключение к базе данных + все переменные окружения должны быть переданные во время билда. Это всё можно реализовать, но это немного концепции докера противоречит. +Менеджмент имеджей на vps не очень приятная штука (надо придумывать механизм всё время старые чистить) Рано или поздно в любом случае в докер проще уйти, но я оттяну немного этот момент

  • @alex91073
    @alex910735 ай бұрын

    Всем привет! благодарю Евгения за видео. у меня возникла проблема, когда гитхаб пытается подключиться к vps. может кто-нибудь помочь советом, как решить задачу? >> Public ssh fingerprint found, man-in-the-middle protection enabled. No ED25519 host key is known for [***]:*** and you have requested strict checking. Host key verification failed.

  • @yakub8798
    @yakub87984 ай бұрын

    привет подскажите пж как получить доступ к 3 видео из плейлиста ?

  • @paromovevg

    @paromovevg

    4 ай бұрын

    Третье видео завтра выйдет

  • @yakub8798

    @yakub8798

    4 ай бұрын

    @@paromovevg понял, спасибо тебе за контент , очень нравятся твои уроки !

  • @user-ke4cy3cl2s
    @user-ke4cy3cl2s4 ай бұрын

    сделай курс по docker

  • @deantek
    @deantek3 ай бұрын

    смотрю эту серию видосов, потому что боюсь завалить испыталку в банке, до этого 4 года на галерах греб, получил оффер в хорошую компанию, а теперь неуверенность меня съедает :`(

  • @tahrizade
    @tahrizade4 ай бұрын

    а как ты монтируешь это видое ? это эже 4 часа и сколько времени уходит на скачивание в youtube ???

  • @paromovevg

    @paromovevg

    4 ай бұрын

    Времени уходит дохера. А так монтирую по частям. По факту тайм коды, это как раз части видоска которые я отдельно монтировал

  • @tahrizade

    @tahrizade

    4 ай бұрын

    @@paromovevg да тоже самое . думал есть какой-то лайф хак ))) тебя тогда желаю удачи чувак :) за видос спасибо

  • @xxcrypt234
    @xxcrypt2344 ай бұрын

    Гигачад

  • @ringnull
    @ringnull4 ай бұрын

    1:39:39 это не синглтон, ты каждый раз при импорте получишь разные объекты

  • @1nightstarlight3
    @1nightstarlight35 ай бұрын

    Царский подгон, выходные уже удались

  • @izzy7541
    @izzy75415 ай бұрын

    На данном этапе, пока проект ещё сырой, тебе вообще юнит тесты не нужны, в них нет никакой практической пользы, только время потратишь. Пиши только е2е пока не сделаешь mvp продукт который будет работать. Дальше уже можешь по этапно внедрять юнит тесты когда они будут необходимы. А то тестировать детали реализации это очень плохо, так делать не надо

  • @paromovevg

    @paromovevg

    5 ай бұрын

    Полностью отрицать юниты точно не стоит, они очень хорошо работают в "сложных" местах. В этом проекте такие будут, так что я решил их здесь использовать Но всё покрывать ими мы конечно не будем

  • @izzy7541

    @izzy7541

    5 ай бұрын

    @@paromovevg Конечно, юниты местами нужны. Но большинство почему то тестируют выполнение кода, мокая каждый чих, забывая что сценарий теста должнен выполняться от лица пользователя

  • @SuperWhiteskull

    @SuperWhiteskull

    4 ай бұрын

    @@izzy7541сценарий теста от пользователя напишет тестировщик, а юнит тесты выполняют другую функцию

  • @wolfern5449
    @wolfern54494 ай бұрын

    А где продолжение, автор?(

  • @paromovevg

    @paromovevg

    4 ай бұрын

    Уже на канале)

  • @denispepper2830
    @denispepper28305 ай бұрын

    fsd - это кринж

  • @rustamakhmetyanov4404

    @rustamakhmetyanov4404

    5 ай бұрын

    ну у сбер с вами не согласится)) у них в вакансиях просят его

  • @Lear-fe6se

    @Lear-fe6se

    5 ай бұрын

    можете предложить альтернативы?

  • @modusvivaldi7701

    @modusvivaldi7701

    2 ай бұрын

    @denispepper2830 Расскажешь, почему кринж?

Келесі