itcloud/tech_spec_cloud_media_stora...

21 KiB
Raw Permalink Blame History

Техническое задание (ТЗ)

Проект: облачное хранилище фото и видео (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 (минимально жизнеспособная версия)

  1. Регистрация/логин (минимум: email+пароль)
  2. Загрузка фото/видео в S3 (через pre-signed URLs)
  3. Библиотека медиа:
    • список/сетка,
    • просмотр (лайтбокс) фото,
    • просмотр/проигрывание видео,
    • базовые сортировки (по дате добавления, по дате съёмки).
  4. Удаление (корзина/soft-delete) и восстановление.
  5. Простой шаринг публичной ссылкой (срок действия).
  6. Генерация превью для изображений (thumbnails).
  7. Хранение метаданных (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)

  1. Как пользователь, я хочу быстро перетащить папку/файлы и загрузить их в облако.
  2. Как пользователь, я хочу просматривать фото в полноэкранном режиме и листать стрелками.
  3. Как пользователь, я хочу смотреть видео прямо в браузере.
  4. Как пользователь, я хочу удалить файлы и при необходимости восстановить из корзины.
  5. Как пользователь, я хочу поделиться ссылкой на один файл/альбом на ограниченное время.

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)

  1. Login / Register
  2. Library (главная)
    • переключатель “Grid / List”,
    • фильтр по типу (photo/video),
    • сортировка,
    • строка поиска (в MVP можно скрыть за feature-flag).
  3. Viewer
    • фото: зум, листание, скачать,
    • видео: плеер (HTML5), скачать.
  4. Upload
    • drag&drop зона,
    • прогресс по файлу и общий прогресс,
    • повтор при ошибке.
  5. Trash
    • список удалённых, restore/purge.
  6. 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 Компоненты

  1. Static SPA (S3 hosting)
  2. Backend API (Python)
  3. Database (SQLite → PostgreSQL)
  4. Object storage (S3)
  5. Background worker (опционально сразу, обязательно для v1) — генерация превью/постеров

5.2 Потоки

Upload (рекомендуемый):

  1. SPA запрашивает у backend create_upload (получает pre-signed URL / multipart init).
  2. SPA грузит файл напрямую в S3.
  3. SPA вызывает finalize_upload (backend фиксирует метаданные, ставит задачу на превью).
  4. 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 middleware
  • services/ — бизнес-логика (upload, library, share)
  • repositories/ — доступ к данным (CRUD)
  • infra/ — S3 client, db session factory, config, background tasks
  • domain/ — модели домена/интерфейсы (по необходимости)

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_hash
  • created_at, updated_at
  • is_active

assets

  • id (UUID)
  • user_id (FK users)
  • type enum: photo|video
  • status enum: uploading|ready|failed|deleted
  • original_filename
  • content_type
  • size_bytes
  • sha256 (optional, for dedup)
  • captured_at (datetime, optional)
  • created_at
  • deleted_at (nullable)
  • storage_key_original (S3 object key)
  • storage_key_thumb (nullable)
  • width, height (nullable)
  • duration_sec (nullable)

albums (v1)

  • id UUID
  • user_id
  • title
  • created_at

album_items (v1)

  • album_id
  • asset_id
  • position (int)

tags (v1)

  • id, user_id, name

asset_tags (v1)

  • asset_id, tag_id

shares

  • id UUID
  • owner_user_id
  • asset_id (nullable) — если шаринг одного файла
  • album_id (nullable) — если шаринг альбома
  • token (unique, random)
  • expires_at (nullable)
  • password_hash (nullable)
  • created_at
  • revoked_at (nullable)

auth_sessions (опционально)

  • id
  • user_id
  • refresh_token_hash
  • created_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: 530 минут,
    • originals: 110 минут (настраиваемо).

9. API (контракт)

9.1 Общие правила

  • Версионирование: /api/v1
  • Авторизация: Authorization: Bearer <token> (или cookie-based)
  • Ответы: JSON
  • Ошибки: единый формат { "error": { "code": "...", "message": "...", "details": ... } }

9.2 Эндпоинты (MVP)

Auth

  • POST /api/v1/auth/register
  • POST /api/v1/auth/login
  • POST /api/v1/auth/logout
  • GET /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}/restore
  • DELETE /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|thumb
  • GET /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_upload backend ставит задачу “generate_thumbnail(asset_id)”.

Режим исполнения (на выбор):

  1. Inline (допустимо в MVP): генерация превью синхронно при finalize, если файл небольшой.
  2. 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: видео постеры

  • Генерация постера (кадр на 13 секунде) через 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 (например 520 ГБ).
  • Для больших файлов — multipart upload (S3 multipart).
  • Лимит выдачи списка: 50200 элементов, 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|prod
  • DATABASE_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=600
  • CORS_ORIGINS=https://your-domain
  • JWT_SECRET=
  • JWT_ACCESS_TTL_SECONDS=900
  • JWT_REFRESH_TTL_SECONDS=1209600
  • MAX_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. Примечания по лицензиям и приватности

  • Пользовательские файлы и метаданные считаются приватными, но админ может всё просматривать.
  • Логи не должны содержать содержимое файлов и чувствительные данные (пароли/токены).
  • При шаринге — показывать минимум метаданных.