Files
enigFM/TECHNICAL_SPEC.md

292 lines
12 KiB
Markdown
Raw Normal View History

2025-12-12 13:30:09 +03:00
# Техническое задание: Совместное прослушивание музыки
## 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. Принятые решения
- **Аутентификация** — обязательная регистрация
- **Права управления** — все участники могут управлять плеером
- **Чат** — текстовый чат в каждой комнате
- **Библиотека музыки** — общая для всех пользователей
- **Приватность** — все комнаты публичные