292 lines
12 KiB
Markdown
292 lines
12 KiB
Markdown
# Техническое задание: Совместное прослушивание музыки
|
||
|
||
## 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) | Уникальное имя пользователя |
|
||
| email | 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. Принятые решения
|
||
|
||
- **Аутентификация** — обязательная регистрация
|
||
- **Права управления** — все участники могут управлять плеером
|
||
- **Чат** — текстовый чат в каждой комнате
|
||
- **Библиотека музыки** — общая для всех пользователей
|
||
- **Приватность** — все комнаты публичные
|