# MyYouTube Персональный YouTube-клиент с категориями подписок и интеграцией с существующим MeTube. Полное техническое задание: [`youtube_categories_metube_TZ.md`](./youtube_categories_metube_TZ.md). UI/UX-спека (дизайн-система и сценарии интерфейса): [`UI_UX_spec.md`](./UI_UX_spec.md). Текущий статус: **функционально готово** (Phases 1-6 из ТЗ + hardening по ходу тестирования). Развёрнуто и вручную протестировано на тестовом окружении (`testmyyoutube.vrubel.xyz` → hermesVM `192.168.8.173` → MeTube на mediaVM `192.168.8.177`). ### Что сделано - Skeleton, Google OAuth (single-user allow-list), sync подписок/видео (APScheduler), категории (CRUD + many-to-many), лента с курсорной пагинацией, YouTube-плеер, полная MeTube-интеграция (download/delete, Socket.IO live-статусы, recovery после рестарта). - Раздел **«На сервере»** — скачанные видео; `/saved` перенаправляет на `/local`. - Тёмный адаптивный интерфейс: общая навигация, категории с постоянными URL, поиск по названиям видео и каналов, мобильное меню. - Отписанные каналы скрываются из списка каналов. - **Отклонение от исходного MVP ТЗ (раздел 2)**: реальная отписка от канала на YouTube (`subscriptions.delete`) реализована по явной просьбе пользователя, хотя ТЗ изначально исключало управление подписками из MVP. Из-за этого OAuth scope расширен с `youtube.readonly` до полного `youtube` (read/write) — см. `backend/app/services/google_oauth.py`. - Удаление скачанного видео с сервера (`DELETE /api/videos/{id}/download`) — тоже сверх исходного MVP-скоупа, добавлено по запросу. ### Что осталось / сознательно отложено - Остальные пункты раздела 35 ТЗ («Возможные улучшения после MVP») не делались: PWA, watch later, Shorts-фильтр, SponsorBlock и т.д. - Формальный Phase 7 hardening из ТЗ (retry/recovery, тесты) закрывался по факту находок в live-тестировании, а не отдельным проходом — см. `git log` для конкретных багфиксов (flapping статусов загрузки, неверный id в MeTube `/delete`, OAuth scope mismatch). ## Стек - Backend: Python 3.13, FastAPI, SQLAlchemy 2.x, Alembic, Pydantic Settings - Frontend: React, TypeScript, Vite, React Router, TanStack Query - DB: PostgreSQL 16 - Deployment: Docker Compose ## Запуск в production (Docker Compose) 1. Скопируй `.env.example` в `.env` и заполни значения (Google OAuth credentials, секреты, MeTube URLs). 2. Собери и запусти: ```bash docker compose up -d --build ``` 3. Проверь health: ```bash curl http://localhost:8080/api/health ``` Миграции Alembic применяются автоматически при старте контейнера `app` (см. `entrypoint.sh`). ## Локальная разработка ### Backend ```bash cd backend uv venv .venv uv pip install -p .venv -r requirements-dev.txt source .venv/bin/activate cd .. DATABASE_URL=postgresql+psycopg://youtube_app:password@localhost:5432/youtube_app \ APP_SECRET_KEY=dev APP_SECRET_KEY=dev TOKEN_ENCRYPTION_KEY=dev \ alembic upgrade head uvicorn app.main:app --reload --app-dir backend --port 8080 ``` Тесты: ```bash backend/.venv/bin/python -m pytest tests/ -v ``` ### Frontend ```bash cd frontend npm install npm run dev ``` Dev-сервер Vite проксирует `/api/*` на `http://127.0.0.1:8080` (см. `vite.config.ts`). ## Миграции ```bash alembic revision -m "описание" alembic upgrade head ``` `alembic.ini` и папка `migrations/` находятся в корне проекта и подключают модели из `backend/app`. ## Структура проекта ```text myyoutube/ ├── backend/ # FastAPI приложение ├── frontend/ # React SPA ├── migrations/ # Alembic migrations ├── tests/ # backend tests (pytest) ├── Dockerfile ├── compose.yml ├── .env / .env.example └── youtube_categories_metube_TZ.md ``` ## Секреты `.env` в `.gitignore`, не коммитится. Обязательные секреты: `APP_SECRET_KEY`, `TOKEN_ENCRYPTION_KEY`, `GOOGLE_CLIENT_SECRET`, `POSTGRES_PASSWORD`.