p1ctos4ve
Проект в рамках дисциплины «Конструирование программного обеспечения»: сервис сохранения и организации медиа со внешних ресурсов
Участники
- Железняков Марк Викторович -
5130904/30105 - Михеев Егор Романович -
5130904/30105 - Михальченко Владислав Сергеевич -
5130904/30105 - Ботыгин Иван Алексеевич -
5130904/30105
Определение проблемы
Пользователи, сохраняющие большое количество медиафайлов (фотографий, видео, GIF) из разных источников (социальные сети, мессенджеры и другие специализированные платформы), сталкиваются с трудностями их систематизации и последующего поиска. Файлы скапливаются в беспорядке, отсутствует единая система тегов и категорий, что делает быстрый поиск нужного материала практически невозможным и требует значительных ручных усилий по организации. При этом всегда присутствует риск удаления материалов из первоисточника.
Выработка требований
Пользовательские истории
- Как пользователь, я хочу добавлять медиафайлы (фото, видео, GIF) в свою библиотеку из различных источников (прямая загрузка, по ссылке, через интеграцию с Tenor/Pinterest), чтобы централизованно хранить все материалы.
- Как пользователь, я хочу иметь мощную систему поиска по библиотеке с фильтрацией по типу файла, тегам, категориям и дате добавления, чтобы быстро находить конкретные материалы.
- Как пользователь, я хочу иметь возможность просматривать свою медиатеку в удобном интерфейсе (галерея, список) с предпросмотром, чтобы легко ориентироваться в содержимом.
Разработка архитектуры и детальное проектирование
Оценка масштаба
Оценка масштаба производится при условии нагрузки на сервис в размере 10 000 активных пользователей в сутки. При этом сервис подазумевает опцию селфхостинга, что может снизить требования к ресурсам центрального экземпляра (инстанса) сервиса.
Характер нагрузки
Соотношение R/W нагрузки
30% на чтение и 70% на запись. Обосновать это можно тем, что запись метаданных и загрузка файлов будет занимать большую долю операций в сервисе с пиками во время массовых импортов из Tenor/Pinterest. При этом чтение данных будет производится сильно реже
Трафик
Для входящего трафика предположим, что один пользователь в среднем будем генерировать 5 МБ данных. Так, 10 000 пользователей * 5 МБ = 50 ГБ/день.
Объемы дисковой системы
При начальном размере файла ~5 МБ и 10 загрузках на пользователя в день: 10 000 * 10 * 5 МБ = 500 ГБ/день. Поэтому может потребоваться дешевое S3-хранилище.
Диаграммы C4 Model
Контекст
Контейнеры
Компоненты
Контракты API
Краткая информация о методах API доступна в assets/API.md, а полная документация - в Scalar на эндпоинте /openapi.
Схема БД и оправдание с точки зрения нефункциональных требований
Нефункциональные требования
Оптимизация индексов и связей
В схеме присутствуют индексы на полях, которые часто участвуют в поисковых запросах, например, 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 в браузере.



