- CI status
- Как запускать Flutter приложение
- GraphQL
- Запросы
- 1. Получение информации о канале
- 2. Получение подписок на каналы пользователя (список каналов, на которые подписан)
- 3. Получение информации о пользователе
- 4. Получение ID канала пользователя
- 5. Получение информации о кошельке пользователя
- 6. Получение информации о видео
- 7. Получение списка видео с пагинацией
- Мутации
- Этап 2 (Flutter)
- Как запускать проект в Docker
- Запуск тестов для всего проекта
Перед стартом мобильного приложения необходимо поднять backend в Docker => гайд.
Flutter приложение не хочет 'дружить' с сервером в Docker на localhost
, поэтому все работает только на веб-версии, команда для запуска:
flutter run -d chrome --web-hostname=localhost --web-port=5000
Основные запросы сделаны на
graphql
через блоки и сервисы, авторизация/регистрация наhttp.post
и моделями для ответов, дополнительно прикручен провайдер =>AuthProvider
.
API позволяет получать и управлять данными пользователей, каналов, видео и кошельков через GraphQL запросы и мутации.
- Все сущности идентифицируются UUID в виде строки.
- Все запросы возвращают поля
isSuccessfully
(булево),message
(текст) для статуса операции. - Для пагинации используются параметры
page
(номер страницы) иsize
(размер страницы).
query {
channel(id: "ab8d5a29-0e4d-4c16-98d3-0ef95e858ad2") {
channel {
id # UUID канала
name # Название канала
subscribers # Количество подписчиков
videoCount # Количество видео на канале
description # Описание канала
mainImage # Идентификатор основного изображения (аватар)
bannerImage # Идентификатор баннера канала
}
}
}
Пример успешного ответа
{
"data": {
"channel": {
"channel": {
"id": "ab8d5a290e4d4c1698d30ef95e858ad2",
"name": "Tamaev TV",
"subscribers": 231232,
"videoCount": 1,
"description": "Это моя машина",
"mainImage": "87be5e57-f447-4b07-aa77-df4f56eabe8e",
"bannerImage": "00000000-0000-0000-0000-000000000000"
}
}
}
}
query {
subsChannel(id: "f73f9ccd-bea8-4bc1-a3b6-01106ef9c997", page: 1, size: 10) {
isSuccessfully # Статус запроса (true/false)
message # Сообщение об ошибке или успехе
channels { # Массив каналов, на которые подписан пользователь
id
name
description
subscribers
videoCount
bannerImage
mainImage
}
}
}
Пример успешного ответа
{
"data": {
"subsChannel": {
"isSuccessfully": true,
"message": null,
"channels": [
{
"id": "ab8d5a290e4d4c1698d30ef95e858ad2",
"name": "Tamaev TV",
"description": "Это моя машина",
"subscribers": 231232,
"videoCount": 1,
"bannerImage": "",
"mainImage": "87be5e57-f447-4b07-aa77-df4f56eabe8e"
}
]
}
}
}
query {
user(id: "1fd36336-44ad-4cc9-9619-12c639c0f6a4") {
isSuccessfully # Статус запроса
message # Сообщение об ошибке или успехе
name # Имя пользователя
surName # Фамилия пользователя
email # Email пользователя
userName # Полное имя / Никнейм
isPremium # Статус премиум-подписки (true/false)
channelId # UUID канала пользователя
}
}
Пример успешного ответа
{
"data": {
"user": {
"isSuccessfully": true,
"message": null,
"name": "Bulat",
"surName": "Nagimullin",
"email": "bulatfri18@gmail.com",
"userName": "Bulat Nagimullin",
"isPremium": false,
"channelId": "f73f9ccdbea84bc1a3b601106ef9c997"
}
}
}
query {
userChannel(id: "1fd36336-44ad-4cc9-9619-12c639c0f6a4") {
isSuccessfully # Статус запроса
message # Сообщение, например, с ID канала
entityId # UUID канала пользователя
}
}
Пример успешного ответа
{
"data": {
"userChannel": {
"isSuccessfully": true,
"message": "User channel id: f73f9ccd-bea8-4bc1-a3b6-01106ef9c997",
"entityId": "f73f9ccdbea84bc1a3b601106ef9c997"
}
}
}
query {
userWallet(id: "0de80c01-b72e-47ce-b864-b9479ce57feb") {
entityId # UUID кошелька
balance # Баланс на кошельке (float)
isSuccessfully # Статус запроса
message # Сообщение об ошибке или успехе
walletId # Идентификатор кошелька (UUID)
}
}
Пример успешного ответа
{
"data": {
"userWallet": {
"entityId": "0de80c01b72e47ceb864b9479ce57feb",
"balance": 100.5,
"isSuccessfully": true,
"message": null,
"walletId": "f37b7c932b0d486c9aacda7f0bbcd4e4"
}
}
}
query {
video(id: "2632bd2f-4db9-4d52-8cf7-18b9d10b05d4") {
isSuccessfully # Статус запроса
channelId # UUID канала, которому принадлежит видео
videoId # UUID видео
video { # Объект с деталями видео
videoFileId # UUID файла видео
previewId # UUID превью видео
viewCount # Количество просмотров
name # Название видео
realiseDate # Дата публикации
channelName # Название канала
}
}
}
Пример успешного ответа
{
"data": {
"video": {
"isSuccessfully": true,
"channelId": "ab8d5a290e4d4c1698d30ef95e858ad2",
"videoId": "2632bd2f4db94d528cf718b9d10b05d4",
"video": {
"videoFileId": "5a691bd70f67497395e95548bdd6e156",
"previewId": "a7774f38c7424e1c9df9ea48e28a8e1b",
"viewCount": 1245,
"name": "Mohito",
"realiseDate": "2025-01-04",
"channelName": "Tamaev TV"
}
}
}
}
query {
videoPagination(page: 1, size: 10) {
isSuccessfully # Статус запроса
message # Сообщение об ошибке или успехе
videos { # Массив видео с деталями
previewUrl # UUID превью картинки
channelImageUrl # UUID картинки канала
videoName # Название видео
views # Количество просмотров
releaseDate # Дата публикации
videoId # UUID видео
channelId # UUID канала
}
}
}
Пример успешного ответа
{
"data": {
"videoPagination": {
"isSuccessfully": true,
"message": null,
"videos": [
{
"previewUrl": "a7774f38-c742-4e1c-9df9-ea48e28a8e1b",
"channelImageUrl": "87be5e57-f447-4b07-aa77-df4f56eabe8e",
"videoName": "Mohito",
"views": 1245,
"releaseDate": "2025-01-04",
"videoId": "2632bd2f4db94d528cf718b9d10b05d4",
"channelId": "ab8d5a290e4d4c1698d30ef95e858ad2"
}
]
}
}
}
mutation {
createWallet(
id: "0de80c01-b72e-47ce-b864-b9479ce57feb",
balance: 100.50
) {
isSuccessfully # Статус операции
message # Сообщение о результате
entityId # UUID созданного кошелька
}
}
Пример успешного ответа
{
"data": {
"createWallet": {
"isSuccessfully": true,
"message": "Wallet created successfully id: b610e492-93bd-4cd2-a0b6-f1f9884fd3f4",
"entityId": "0de80c01b72e47ceb864b9479ce57feb"
}
}
}
Страницы:
-
Главная (список с видео)
-
Плеер
-
Подписки
-
Профиль
-
YouTube Premium (+ 2 модалки-заглушки)
-
Авторизация и регистрация
Открывается при запуске приложения, попасть можно через нижний навбар:
При нажатии на видео откроется страница плеера
Для плеера использовали готовое решение.
Экран с каналами, на которые подписан пользователь, попасть можно через нижний навбар.
Экран профиля пользователя, при выходе из аккаунта на странице будет показано соотвествующее сообщение, с возможностью перехода на экран авторизации.
Страница с описанием фич подписки, плюс две модалки-заглушки, которые будут использованы для пополнения баланса и покупки подписки
Экраны для авторизации/регистрации без валидации, просто макеты, для входа в аккаунт/регистрации достаточно просто нажать на кнопку
После входа/регистрации - редирект на экран профиля, делали регистрацию с помощью провайдера, вынесли его отдельно, для отслеживания состояния пользователя (авторизован или нет, нужно на экране профиля)
В корневой папке нужно ввести команду make docker
, чтобы поднять все контейнеры.
Если Makefile
не установлен:
docker:
docker-compose -f frontend/docker-compose.yml down --rmi all -v
docker-compose -f frontend/docker-compose.yml up --build -d
docker-compose -f backend/Youtube/docker-compose.yml down --rmi all -v
docker-compose -f backend/Youtube/docker-compose.yml up --build -d
tests:
cd frontend/youtube-frontend && npm install
cd frontend/youtube-accounts && npm install
cd frontend/youtube-frontend-tests && npm install && npm run test
cd backend/Youtube && dotnet test --no-build --verbosity normal --collect:"XPlat Code Coverage" --settings ../../.github/coverlet.runsettings
docker-backend:
docker-compose -f backend/Youtube/docker-compose.yml down --rmi all -v
docker-compose -f backend/Youtube/docker-compose.yml up --build -d
Чтобы поднять бэкенд
В результате должен быть примерно такой вывод:
В корневой папке нужно ввести команду make tests
. Запустятся тесты как для фронтенда, так и для бэкенда.
В консоли должен появиться такой вывод с результатми тестов: