# p1ctos4ve Проект в рамках дисциплины «Конструирование программного обеспечения»: сервис сохранения и организации медиа со внешних ресурсов ## Участники - Железняков Марк Викторович - `5130904/30105` - Михеев Егор Романович - `5130904/30105` - Михальченко Владислав Сергеевич - `5130904/30105` - Ботыгин Иван Алексеевич - `5130904/30105` ## Определение проблемы Пользователи, сохраняющие большое количество медиафайлов (фотографий, видео, GIF) из разных источников (социальные сети, мессенджеры и другие специализированные платформы), сталкиваются с трудностями их систематизации и последующего поиска. Файлы скапливаются в беспорядке, отсутствует единая система тегов и категорий, что делает быстрый поиск нужного материала практически невозможным и требует значительных ручных усилий по организации. При этом всегда присутствует риск удаления материалов из первоисточника. ## Выработка требований ### Пользовательские истории 1. Как пользователь, я хочу добавлять медиафайлы (фото, видео, GIF) в свою библиотеку из различных источников (прямая загрузка, по ссылке, через интеграцию с Tenor/Pinterest), чтобы централизованно хранить все материалы. 2. Как пользователь, я хочу иметь мощную систему поиска по библиотеке с фильтрацией по типу файла, тегам, категориям и дате добавления, чтобы быстро находить конкретные материалы. 3. Как пользователь, я хочу иметь возможность просматривать свою медиатеку в удобном интерфейсе (галерея, список) с предпросмотром, чтобы легко ориентироваться в содержимом. ## Разработка архитектуры и детальное проектирование ### Оценка масштаба > Оценка масштаба производится при условии нагрузки на сервис в размере 10 000 активных пользователей в сутки. При этом сервис подазумевает опцию селфхостинга, что может снизить требования к ресурсам центрального экземпляра (инстанса) сервиса. #### Характер нагрузки ##### Соотношение R/W нагрузки **70% на чтение и 30% на запись.** Обосновать это можно тем, что запись метаданных и загрузка файлов будет занимать большую долю операций в сервисе с пиками во время массовых импортов из Tenor/Pinterest. При этом чтение данных будет производится сильно реже ##### Трафик Для входящего трафика предположим, что один пользователь в среднем будем генерировать 10 МБ данных. Так, 10 000 пользователей * 10 МБ = 100 ГБ/день. ##### Объемы дисковой системы При начальном размере файла ~5 МБ и 10 загрузках на пользователя в день: 10 000 * 10 * 5 МБ = 500 ГБ/день. Поэтому может потребоваться дешевое S3-хранилище. ### Диаграммы C4 Model #### Контекст [[assets/c4-1context.jpg]] #### Контейнеры [[assets/c4-2containers.jpg]] #### Компоненты [[assets/c4-3components.jpg]] ### Контракты API Краткая информация о методах API доступна в [assets/API.md](assets/API.md), а полная документация - в [Scalar](https://scalar.com/) на эндпоинте `/openapi`. ### Схема БД и оправдание с точки зрения нефункциональных требований [[assets/db.png]] #### Нефункциональные требвания ##### Оптимизация индексов и связей В схеме присутствуют индексы на полях, которые часто участвуют в поисковых запросах, например, `userId`, `visibility`, `shareUrl`, `tags`. Это повышает производительность выборок и операций поиска. Наличие внешних ключей с каскадным удалением гарантирует целостность данных и упрощает управление связанными данными между таблицами. ##### Масштабируемость и расширяемость Пользователи, сессии и аккаунты разделены по разным таблицам - это упрощает работу и интеграцию способов авторизации пользователей в сервисе. ##### Безопасность и уникальность данных Схема предотвращает дублирование данных посредством использования уникальных индексов. Например, на email и token в сессиях, shareUrl в сейвах. ### Схема масштабирования сервиса при росте нагрузки в 10 раз Для возможности масштабирования можно использовать следующие подходы: - Размещение бекенда за балансировщиком нагрузки (например, Nginx, Traefik или Caddy): трафик будет распределяться равномерно между двумя или более экземплярами API - Репликация БД - основная база принимает запись, а одна или несколько реплик получают изменения по журналу (WAL) и обслуживают преимущественно чтение. - Кеширование частозапрашиваемых данных через Redis: результаты чтения (например, списки, карточки по ID, агрегации, результаты поиска с популярными фильтрами) складываются в KV хранилище с некоторым TTL, что позволяет сократить время ответа на повторяющиеся запросы ## Кодирование и отладка Для разработки сервиса был использован следующий набор технологий: **Бекенд** - *Bun* в качестве рантайма - Бекенд-фреймворк *Elysia* - *Drizzle ORM* для работы с базой данных *PostgreSQL* - Фреймворк *Better Auth* для авторизации и аутентификаци пользователей - *SeaweedFS* для хранения UGC - *Redis* для кеширования частозапрашиваемых данных **Фронтенд** - Фреймворк и библиотеки *Expo* для реализации мобильного клиента сервиса - *Tailwind* + *Nativewind* для стилизации - Набор иконок *Lucide* Для запуска в режиме разработки нужно: **Бекенд** - Установить зависимости: `bun i` - В директории `apps/backend` заполнить файл `.env` на основе `.env.example` - Прописать `bun dev` в директории бекенда или `bun backend:dev` в корне репозитория **Фронтенд** - В директории `apps/frontend` заполнить файл `.env` на основе `.env.example` - Прописать `bun start` в директории фронтенда. Приложение можно отлаживать на мобильном устройстве через песочницу Expo Go. ## Unit-тестирование В проекте есть тесты, проверяющие корректность работы отдельных элементов сервисов бекенда: - `s3.service.test.ts` - проверяет корректность работы автоопределения типов медиа - `saves.service.test.ts` - моковые тесты для проверки работы сервиса сейвов - `scraper.service.test.ts` - тесты для проверки работы вычисления типов медиа на основе URL Для запуска требуется прописать `bun run test:unit` из директории `apps/backend`. ## Интеграционное тестирование Также реализованы e2e-тесты для проверки авторизации и сейвов. Предварительно запустив бекенд, из директории бекенда нужно запустить `bun run test:e2e`. ## Сборка и запуск Для запуска бекенда и его зависимостей на продакшене достаточно выполнить: ``` git clone https://git.inkling.su/p1ctos4ve/app p1ctos4ve cd p1ctos4ve chmod +x ./scripts/run.sh ./scripts/run.sh ``` Скрипт `run.sh`: - Запустит PostgreSQL, SeaweedFS и Redis; - Соберет образ бекенда в Docker-контейнер; - Запустит unit и e2e-тесты; - Поднимет сервер бекенда на `localhost:3000` В дальнейшем для взаимодействия с API можно открыть Scalar на `localhost:3000/openapi` в браузере.