12 KiB
12 KiB
Техническое задание: Совместное прослушивание музыки
1. Описание продукта
Веб-приложение для синхронного прослушивания музыки с друзьями в реальном времени. Пользователи создают комнаты, приглашают друзей по ссылке и слушают музыку одновременно.
2. Основные функции
2.1 Комнаты
- Создание комнаты (генерация уникального ID/ссылки)
- Публичные комнаты с возможностью поиска/списка
- Присоединение по ссылке или из списка комнат
- Отображение списка участников
2.2 Музыкальный плеер
- Воспроизведение MP3 из S3-хранилища
- Синхронизация playback между всеми участниками
- Управление доступно всем участникам: play/pause, перемотка, следующий/предыдущий трек
- Громкость (локальная, у каждого своя)
- Очередь воспроизведения (playlist)
- Отображение текущего трека, прогресса
2.3 Чат
- Текстовый чат внутри комнаты
- Сообщения видны всем участникам в реальном времени
2.4 Управление треками
- Загрузка MP3 файлов в S3
- Общая библиотека треков (доступна всем пользователям во всех комнатах)
- Добавление треков в очередь
- Базовые метаданные: название, исполнитель
2.5 Пользователи
- Обязательная регистрация/авторизация
- Профиль пользователя
3. Технические требования
3.1 Стек технологий
Frontend:
- Vue 3 (Composition API)
- Pinia (state management)
- Vue Router
- WebSocket клиент для real-time
Backend:
- Python
- FastAPI (REST API + WebSocket)
- SQLAlchemy (ORM)
- Alembic (миграции)
База данных:
- PostgreSQL
Хранилище файлов:
- S3 (FirstVDS)
3.2 Синхронизация
- WebSocket для real-time коммуникации
- Компенсация сетевой задержки
- Периодическая синхронизация позиции трека
3.3 Хранилище
- S3 (FirstVDS) для MP3 файлов
- Presigned URLs для безопасного доступа к файлам
- Ограничение размера файла: 10MB
- Лимит общего объёма хранилища: 90GB (проверка перед загрузкой)
3.4 Масштабируемость
- Лимит участников на комнату (например, 50)
- Автоудаление неактивных комнат
4. Схема базы данных
users
| Поле | Тип | Описание |
|---|---|---|
| id | UUID | Первичный ключ |
| username | VARCHAR(50) | Уникальное имя пользователя |
| VARCHAR(255) | Email (уникальный) | |
| password_hash | VARCHAR(255) | Хэш пароля |
| created_at | TIMESTAMP | Дата регистрации |
rooms
| Поле | Тип | Описание |
|---|---|---|
| id | UUID | Первичный ключ |
| name | VARCHAR(100) | Название комнаты |
| owner_id | UUID (FK) | Создатель комнаты |
| current_track_id | UUID (FK) | Текущий трек |
| playback_position | INTEGER | Позиция воспроизведения (мс) |
| is_playing | BOOLEAN | Играет ли сейчас |
| created_at | TIMESTAMP | Дата создания |
tracks
| Поле | Тип | Описание |
|---|---|---|
| id | UUID | Первичный ключ |
| title | VARCHAR(255) | Название трека |
| artist | VARCHAR(255) | Исполнитель |
| duration | INTEGER | Длительность (мс) |
| s3_key | VARCHAR(500) | Путь к файлу в S3 |
| uploaded_by | UUID (FK) | Кто загрузил |
| created_at | TIMESTAMP | Дата загрузки |
room_queue
| Поле | Тип | Описание |
|---|---|---|
| id | UUID | Первичный ключ |
| room_id | UUID (FK) | Комната |
| track_id | UUID (FK) | Трек |
| position | INTEGER | Позиция в очереди |
| added_by | UUID (FK) | Кто добавил |
room_participants
| Поле | Тип | Описание |
|---|---|---|
| room_id | UUID (FK) | Комната |
| user_id | UUID (FK) | Пользователь |
| joined_at | TIMESTAMP | Время входа |
messages
| Поле | Тип | Описание |
|---|---|---|
| id | UUID | Первичный ключ |
| room_id | UUID (FK) | Комната |
| user_id | UUID (FK) | Автор |
| text | TEXT | Текст сообщения |
| created_at | TIMESTAMP | Время отправки |
5. API Endpoints
Аутентификация
POST /api/auth/register— регистрацияPOST /api/auth/login— входPOST /api/auth/logout— выходGET /api/auth/me— текущий пользователь
Комнаты
GET /api/rooms— список публичных комнатPOST /api/rooms— создать комнатуGET /api/rooms/{id}— информация о комнатеDELETE /api/rooms/{id}— удалить комнату (только владелец)POST /api/rooms/{id}/join— присоединитьсяPOST /api/rooms/{id}/leave— покинуть
Плеер (через REST + WebSocket)
POST /api/rooms/{id}/play— воспроизвестиPOST /api/rooms/{id}/pause— паузаPOST /api/rooms/{id}/seek— перемоткаPOST /api/rooms/{id}/next— следующий трекPOST /api/rooms/{id}/prev— предыдущий трек
Очередь
GET /api/rooms/{id}/queue— очередь трековPOST /api/rooms/{id}/queue— добавить трек в очередьDELETE /api/rooms/{id}/queue/{track_id}— убрать из очереди
Треки
GET /api/tracks— библиотека трековPOST /api/tracks/upload— загрузить трекDELETE /api/tracks/{id}— удалить трек
Чат
GET /api/rooms/{id}/messages— история сообщений
WebSocket
WS /ws/rooms/{id}— real-time события комнаты (синхронизация плеера, чат, участники)
6. Структура проекта
enigfm/
├── backend/
│ ├── app/
│ │ ├── __init__.py
│ │ ├── main.py # Точка входа FastAPI
│ │ ├── config.py # Конфигурация (env переменные)
│ │ ├── database.py # Подключение к БД
│ │ │
│ │ ├── models/ # SQLAlchemy модели
│ │ │ ├── __init__.py
│ │ │ ├── user.py
│ │ │ ├── room.py
│ │ │ ├── track.py
│ │ │ └── message.py
│ │ │
│ │ ├── schemas/ # Pydantic схемы
│ │ │ ├── __init__.py
│ │ │ ├── user.py
│ │ │ ├── room.py
│ │ │ ├── track.py
│ │ │ └── message.py
│ │ │
│ │ ├── routers/ # API роуты
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── rooms.py
│ │ │ ├── tracks.py
│ │ │ └── websocket.py
│ │ │
│ │ ├── services/ # Бизнес-логика
│ │ │ ├── __init__.py
│ │ │ ├── auth.py
│ │ │ ├── room.py
│ │ │ ├── track.py
│ │ │ ├── s3.py # Работа с S3
│ │ │ └── sync.py # Синхронизация плеера
│ │ │
│ │ └── utils/ # Утилиты
│ │ ├── __init__.py
│ │ └── security.py # JWT, хэширование
│ │
│ ├── alembic/ # Миграции БД
│ │ ├── versions/
│ │ └── env.py
│ │
│ ├── tests/
│ ├── requirements.txt
│ ├── alembic.ini
│ └── .env.example
│
├── frontend/
│ ├── src/
│ │ ├── main.js # Точка входа
│ │ ├── App.vue
│ │ │
│ │ ├── components/ # Vue компоненты
│ │ │ ├── player/
│ │ │ │ ├── AudioPlayer.vue
│ │ │ │ ├── PlayerControls.vue
│ │ │ │ ├── ProgressBar.vue
│ │ │ │ └── VolumeControl.vue
│ │ │ ├── room/
│ │ │ │ ├── RoomCard.vue
│ │ │ │ ├── RoomList.vue
│ │ │ │ ├── ParticipantsList.vue
│ │ │ │ └── Queue.vue
│ │ │ ├── chat/
│ │ │ │ ├── ChatWindow.vue
│ │ │ │ └── ChatMessage.vue
│ │ │ ├── tracks/
│ │ │ │ ├── TrackList.vue
│ │ │ │ ├── TrackItem.vue
│ │ │ │ └── UploadTrack.vue
│ │ │ └── common/
│ │ │ ├── Header.vue
│ │ │ └── Modal.vue
│ │ │
│ │ ├── views/ # Страницы
│ │ │ ├── HomeView.vue # Список комнат
│ │ │ ├── RoomView.vue # Страница комнаты
│ │ │ ├── LoginView.vue
│ │ │ ├── RegisterView.vue
│ │ │ └── TracksView.vue # Библиотека треков
│ │ │
│ │ ├── stores/ # Pinia stores
│ │ │ ├── auth.js
│ │ │ ├── room.js
│ │ │ ├── player.js
│ │ │ └── tracks.js
│ │ │
│ │ ├── composables/ # Vue composables
│ │ │ ├── useWebSocket.js
│ │ │ ├── usePlayer.js
│ │ │ └── useApi.js
│ │ │
│ │ ├── router/
│ │ │ └── index.js
│ │ │
│ │ └── assets/
│ │ └── styles/
│ │
│ ├── public/
│ ├── package.json
│ ├── vite.config.js
│ └── .env.example
│
├── docker-compose.yml # PostgreSQL, Backend, Frontend
├── .gitignore
└── README.md
7. Принятые решения
- Аутентификация — обязательная регистрация
- Права управления — все участники могут управлять плеером
- Чат — текстовый чат в каждой комнате
- Библиотека музыки — общая для всех пользователей
- Приватность — все комнаты публичные