21 KiB
Техническое задание (ТЗ)
Проект: облачное хранилище фото и видео (S3 + Python backend + SQLite → PostgreSQL)
Формат фронтенда: статический сайт (SPA) в папке static/, хостинг в S3
UI: Material UI (MUI)
Backend: Python (FastAPI)
Хранилище файлов: S3 / S3-compatible (MinIO и т.п.)
База данных: SQLite на старте, в будущем — PostgreSQL (миграции через Alembic)
1. Цели и принципы
1.1 Цель продукта
Создать удобное, быстрое и безопасное облачное хранилище для фото и видео с фокусом на:
- максимально простой и быстрый загрузчик (drag&drop, пакетные загрузки, большие файлы);
- удобную библиотеку (лента/сеткой), быстрый просмотр, поиск/фильтры;
- безопасный доступ и шаринг ссылками;
- готовность к росту: миграция SQLite → PostgreSQL без переписывания бизнес-логики.
1.2 Принципы реализации
- SOLID / DRY / Clean Architecture: разделение слоёв (API → Service → Repository → Infrastructure).
- Докстринги обязательны для публичных методов/классов и основных сервисов.
- Минимум комментариев в коде: предпочтение самодокументирующемуся коду и докстрингам.
- Стабильный API-контракт: OpenAPI/Swagger (FastAPI).
- Сразу закладываем расширяемость (теги, альбомы, шаринг, фоновые задачи).
2. Область охвата (Scope)
2.1 MVP (минимально жизнеспособная версия)
- Регистрация/логин (минимум: email+пароль)
- Загрузка фото/видео в S3 (через pre-signed URLs)
- Библиотека медиа:
- список/сетка,
- просмотр (лайтбокс) фото,
- просмотр/проигрывание видео,
- базовые сортировки (по дате добавления, по дате съёмки).
- Удаление (корзина/soft-delete) и восстановление.
- Простой шаринг публичной ссылкой (срок действия).
- Генерация превью для изображений (thumbnails).
- Хранение метаданных (SQLite), подготовлено для PostgreSQL (ORM + миграции).
2.2 Версия v1 (после MVP)
- Альбомы/папки (логическая группировка).
- Теги и поиск по тегам/дате/типу/размеру.
- Извлечение EXIF (камера, дата съёмки, гео — опционально).
- Превью/постер для видео.
- Множественный выбор, пакетные операции (переместить/удалить/добавить теги).
- Пользовательские квоты и статистика хранения.
- Логи действий (аудит: загрузка/удаление/шаринг).
2.3 Вне рамок (Non-goals) на старте
- Полноценное видеотранскодирование в HLS/DASH.
- Распознавание лиц/умные альбомы.
- Коллаборация “семейные библиотеки” (несколько владельцев одного альбома).
- End-to-end шифрование на клиенте.
3. Роли и сценарии
3.1 Роли
- User: загружает и управляет своей медиатекой.
- Admin (опционально в v1): администрирование пользователей/квот и доступ ко всем облакам пользователей.
3.2 Ключевые user stories (MVP)
- Как пользователь, я хочу быстро перетащить папку/файлы и загрузить их в облако.
- Как пользователь, я хочу просматривать фото в полноэкранном режиме и листать стрелками.
- Как пользователь, я хочу смотреть видео прямо в браузере.
- Как пользователь, я хочу удалить файлы и при необходимости восстановить из корзины.
- Как пользователь, я хочу поделиться ссылкой на один файл/альбом на ограниченное время.
4. UX/UI требования (фронтенд)
4.1 Технологическое решение фронтенда
Рекомендуемый компромисс “JS чистый + MUI”:
- Реализовать SPA на React + MUI,
- Сборка (Vite) выдаёт статические артефакты в
static/, - На проде в S3 лежит только
static/(HTML/CSS/JS).
Важно: Material UI (MUI) — React-библиотека. “Чистый JS без сборки” возможен через CDN + UMD, но это хуже по производительности и DX. В ТЗ закладываем правильную схему: разработка с Vite, деплой артефактов в
static/.
4.2 Страницы/экраны (MVP)
- Login / Register
- Library (главная)
- переключатель “Grid / List”,
- фильтр по типу (photo/video),
- сортировка,
- строка поиска (в MVP можно скрыть за feature-flag).
- Viewer
- фото: зум, листание, скачать,
- видео: плеер (HTML5), скачать.
- Upload
- drag&drop зона,
- прогресс по файлу и общий прогресс,
- повтор при ошибке.
- Trash
- список удалённых, restore/purge.
- Shared view (страница по публичной ссылке)
4.3 Компоненты UI
- AppBar + боковое меню (Drawer)
- MediaGrid (виртуализация списка, infinite scroll)
- MediaCard (thumbnail, иконка видео, размер/дата)
- UploadDialog (dropzone + очередь + прогресс)
- ViewerModal (keyboard nav: ← → Esc)
- FiltersBar (chips/select)
4.4 Нефункциональные требования к UI
- Responsive: desktop-first, корректно на мобилках.
- Оптимизация:
- thumbnails грузятся лениво,
- viewer тянет оригинал только по запросу,
- infinite scroll.
- Удобство:
- drag&drop в любом месте Library,
- горячие клавиши в Viewer,
- понятные ошибки и “повторить загрузку”.
5. Архитектура (общая)
5.1 Компоненты
- Static SPA (S3 hosting)
- Backend API (Python)
- Database (SQLite → PostgreSQL)
- Object storage (S3)
- Background worker (опционально сразу, обязательно для v1) — генерация превью/постеров
5.2 Потоки
Upload (рекомендуемый):
- SPA запрашивает у backend
create_upload(получает pre-signed URL / multipart init). - SPA грузит файл напрямую в S3.
- SPA вызывает
finalize_upload(backend фиксирует метаданные, ставит задачу на превью). - Backend возвращает Asset ID.
Download/View:
- SPA запрашивает
get_asset_download_url→ получает краткоживущую signed-ссылку на S3 (оригинал/thumbnail).
6. Backend требования
6.1 Стек (рекомендуется)
- FastAPI (ASGI)
- Pydantic (схемы)
- SQLAlchemy 2.x (async) + Alembic (миграции)
- SQLite (MVP), конфигурация диалекта для лёгкого перехода на PostgreSQL
- S3 SDK: boto3 (sync) или aioboto3 (async) / или минимальный клиент через presigned
- Auth: JWT access + refresh (HTTP-only cookies) или Bearer tokens
- Logging: structlog/loguru + стандартный logging
- Tests: pytest + httpx
6.2 Слоистая архитектура (Clean)
api/— роуты, схемы, зависимости, auth middlewareservices/— бизнес-логика (upload, library, share)repositories/— доступ к данным (CRUD)infra/— S3 client, db session factory, config, background tasksdomain/— модели домена/интерфейсы (по необходимости)
6.3 Обязательные нефункциональные требования
- Валидация входных данных (Pydantic).
- Единый формат ошибок (problem+json либо собственный стандарт).
- Rate limiting (минимально на login/share) — можно отложить до v1.
- Безопасность:
- пароли хранить только в виде хеша (argon2/bcrypt),
- все ссылки на S3 — только signed,
- CORS настроен строго,
- CSRF защита при cookie-based auth.
- Наблюдаемость:
- структурные логи,
- correlation id (request id),
- healthcheck endpoint.
7. Модель данных (SQLite → PostgreSQL)
7.1 Основные сущности
users
id(UUID)email(unique)password_hashcreated_at,updated_atis_active
assets
id(UUID)user_id(FK users)typeenum:photo|videostatusenum:uploading|ready|failed|deletedoriginal_filenamecontent_typesize_bytessha256(optional, for dedup)captured_at(datetime, optional)created_atdeleted_at(nullable)storage_key_original(S3 object key)storage_key_thumb(nullable)width,height(nullable)duration_sec(nullable)
albums (v1)
idUUIDuser_idtitlecreated_at
album_items (v1)
album_idasset_idposition(int)
tags (v1)
id,user_id,name
asset_tags (v1)
asset_id,tag_id
shares
idUUIDowner_user_idasset_id(nullable) — если шаринг одного файлаalbum_id(nullable) — если шаринг альбомаtoken(unique, random)expires_at(nullable)password_hash(nullable)created_atrevoked_at(nullable)
auth_sessions (опционально)
iduser_idrefresh_token_hashcreated_at,expires_at,revoked_at
7.2 Требования к миграциям
- Все изменения БД — только через Alembic.
- Никаких raw SQL “внутри приложения”, кроме миграций.
- Схема должна работать в SQLite и PostgreSQL:
- UUID хранить как TEXT (SQLite) и UUID (PostgreSQL) через тип-переопределения,
- JSON поля избегать в MVP (или хранить TEXT).
8. Object Storage (S3)
8.1 Bucket и ключи
- Bucket:
MEDIA_BUCKET - Ключ оригинала:
u/{user_id}/o/{yyyy}/{mm}/{asset_id}{ext} - Ключ превью:
u/{user_id}/t/{yyyy}/{mm}/{asset_id}.jpg - (v1) ключ постера для видео:
u/{user_id}/p/{yyyy}/{mm}/{asset_id}.jpg
8.2 Политики доступа
- Bucket private.
- Доступ только через pre-signed URLs с коротким TTL:
- thumbnails: 5–30 минут,
- originals: 1–10 минут (настраиваемо).
9. API (контракт)
9.1 Общие правила
- Версионирование:
/api/v1 - Авторизация:
Authorization: Bearer <token>(или cookie-based) - Ответы: JSON
- Ошибки: единый формат
{ "error": { "code": "...", "message": "...", "details": ... } }
9.2 Эндпоинты (MVP)
Auth
POST /api/v1/auth/registerPOST /api/v1/auth/loginPOST /api/v1/auth/logoutGET /api/v1/auth/me- (опц)
POST /api/v1/auth/refresh
Assets (library)
GET /api/v1/assets?cursor=&limit=&type=&sort=GET /api/v1/assets/{asset_id}DELETE /api/v1/assets/{asset_id}(soft-delete)POST /api/v1/assets/{asset_id}/restoreDELETE /api/v1/assets/{asset_id}/purge(hard-delete, только из Trash)
Upload (direct-to-S3)
POST /api/v1/uploads/create- вход:
original_filename, content_type, size_bytes - выход:
asset_id, upload_method, presigned_url|presigned_post|multipart
- вход:
POST /api/v1/uploads/{asset_id}/finalize- вход:
etag(или parts list),sha256(опц) - выход:
asset
- вход:
URLs (signed access)
GET /api/v1/assets/{asset_id}/download-url?kind=original|thumbGET /api/v1/assets/{asset_id}/stream-url(для видео, kind=original на старте)
Shares
POST /api/v1/shares(создать ссылку)GET /api/v1/shares/{token}(получить метаданные)GET /api/v1/shares/{token}/download-url?asset_id=&kind=POST /api/v1/shares/{token}/revoke
9.3 Пагинация
- Cursor-based (рекомендуется):
cursor= base64(last_created_at, last_id) - Ответ:
{ items: [...], next_cursor: "...", has_more: true }
10. Превью (thumbnails) и обработка
10.1 MVP: только изображения
- После
finalize_uploadbackend ставит задачу “generate_thumbnail(asset_id)”.
Режим исполнения (на выбор):
- Inline (допустимо в MVP): генерация превью синхронно при finalize, если файл небольшой.
- Background worker (лучше): Celery/RQ + Redis, либо встроенный простейший worker.
Рекомендуемый минимум:
- Redis + RQ.
10.2 Технические требования к thumbnails
- Формат: JPEG
- Максимальная сторона: 512px или 1024px (настраиваемо)
- Прогрессивный JPEG (желательно)
- Сохранение в S3 по
storage_key_thumb - При ошибке:
assets.status = failedили отдельное полеthumb_status
10.3 v1: видео постеры
- Генерация постера (кадр на 1–3 секунде) через ffmpeg.
- Хранение отдельным ключом.
11. Безопасность
11.1 Аутентификация и пароли
- Хэширование argon2id (предпочтительно) или bcrypt.
- Ограничение попыток логина (v1).
- Сессии/refresh токены можно отзывать.
11.2 Доступ к файлам
- Все доступы к S3 только через signed URLs.
- Проверка владения asset’ом во всех endpoints.
- Подпись ссылок короткая и на конкретный объект.
11.3 Публичные ссылки
- token должен быть криптостойким (>= 128 бит энтропии).
- Возможность ограничить срок действия.
- (v1) опциональный пароль на ссылку.
12. Производительность и ограничения
12.1 Ограничения MVP
- Максимальный размер видео: конфиг
MAX_UPLOAD_SIZE_BYTES(например 5–20 ГБ). - Для больших файлов — multipart upload (S3 multipart).
- Лимит выдачи списка: 50–200 элементов, infinite scroll.
12.2 Кэширование
- Thumbnails: CDN-friendly, но доступ через signed URL (TTL).
- Статические файлы фронтенда: cache-control immutable для hashed assets.
13. Конфигурация (env)
13.1 Backend env variables (пример)
APP_ENV=dev|prodDATABASE_URL=sqlite+aiosqlite:///./app.db(позже:postgresql+asyncpg://...)S3_ENDPOINT_URL=(если MinIO)S3_REGION=S3_ACCESS_KEY_ID=S3_SECRET_ACCESS_KEY=MEDIA_BUCKET=SIGNED_URL_TTL_SECONDS=600CORS_ORIGINS=https://your-domainJWT_SECRET=JWT_ACCESS_TTL_SECONDS=900JWT_REFRESH_TTL_SECONDS=1209600MAX_UPLOAD_SIZE_BYTES=
14. Деплой и окружения
14.1 Static (S3)
- Папка
static/заливается в S3 bucket для сайта.
14.2 Backend
- Docker-образ, запускается как контейнер (uvicorn/gunicorn).
- Рекомендуемый
docker-composeдля dev: backend + minio + sqlite (локально) + redis.
14.3 База данных
- MVP: SQLite файл в volume.
- v1: PostgreSQL отдельным сервисом, переключение через
DATABASE_URL+ миграции alembic.
15. Структура репозитория (рекомендация)
repo/
backend/
src/
app/
api/
v1/
services/
repositories/
infra/
domain/
main.py
alembic/
tests/
pyproject.toml
Dockerfile
frontend/
src/
public/
vite.config.js
package.json
static/ # build output (deploy to S3)
docker-compose.yml
README.md
16. Критерии приёмки (Acceptance Criteria)
16.1 MVP
- Пользователь может зарегистрироваться/войти.
- Пользователь может загрузить:
- минимум 1 фото и 1 видео,
- пакет из 100+ фото,
- большой файл (в пределах лимита), без падения сервера.
- В библиотеке отображаются thumbnails для фото.
- Просмотр фото/видео работает в браузере.
- Удаление перемещает в корзину, restore возвращает.
- Public share link открывается без логина (если активен) и даёт доступ только к расшаренному объекту.
- База — SQLite, миграции работают, есть путь миграции на PostgreSQL (без изменения кода сервисов).
16.2 Качество кода
- Линтер/форматтер настроен (ruff + black или ruff format).
- Тесты покрывают ключевые сценарии (auth, create/finalize upload, list assets, share).
- Докстринги присутствуют в слоях services/repositories/infra.
17. План работ (укрупнённо)
Этап 1 — фундамент (1)
- Скелет backend (FastAPI), конфиг, подключение БД, миграции.
- User + Auth (register/login/me).
- S3 интеграция: pre-signed upload + signed download.
Этап 2 — assets (2)
- CRUD метаданных assets.
- Library list с пагинацией.
- Trash (soft-delete/restore/purge).
Этап 3 — frontend MVP (3)
- Login/Register.
- Library grid + infinite scroll.
- Upload dialog + прогресс.
- Viewer modal.
- Trash page.
Этап 4 — thumbnails (4)
- Генерация превью (inline или background).
- Отображение превью в Library.
Этап 5 — shares (5)
- Создание/открытие share links.
- Shared view UI.
18. Риски и решения
- Большие видео: сразу закладываем multipart upload, иначе упремся в лимиты/таймауты.
- MUI и “чистый JS”: реальный путь — React+MUI и сборка в
static/. - SQLite ограничения: используем репозитории/ORM и Alembic, чтобы миграция на PostgreSQL была сменой
DATABASE_URL. - Стоимость S3: thumbnails уменьшают трафик; оригиналы только по запросу.
19. Доп. ПО (если понадобятся очереди/воркеры)
- Redis (рекомендуется)
- RQ (проще)
- Для видео в v1: ffmpeg (в контейнере воркера)
20. Примечания по лицензиям и приватности
- Пользовательские файлы и метаданные считаются приватными, но админ может всё просматривать.
- Логи не должны содержать содержимое файлов и чувствительные данные (пароли/токены).
- При шаринге — показывать минимум метаданных.