299 lines
12 KiB
Markdown
299 lines
12 KiB
Markdown
# 100 к 1 - Multiplayer Game
|
||
|
||
Интерактивная веб-игра "100 к 1" с поддержкой мультиплеера.
|
||
|
||
## 🎮 Возможности
|
||
|
||
### 🌐 Мультиплеер
|
||
- **Игровые комнаты** с уникальными кодами
|
||
- **QR-коды** для быстрого присоединения
|
||
- **Real-time синхронизация** через WebSocket
|
||
- **Роли**: Ведущий, Игрок, Зритель
|
||
- **Статистика игр** с историей
|
||
|
||
## 🛠 Технологический стек
|
||
|
||
### Frontend
|
||
- **React 18.2** + **Vite 5.0**
|
||
- **React Router v6** - маршрутизация
|
||
- **Socket.IO Client** - WebSocket
|
||
- **Axios** - HTTP клиент
|
||
- **QRCode** - генерация QR-кодов
|
||
|
||
### Backend
|
||
- **NestJS** - TypeScript фреймворк
|
||
- **PostgreSQL** - база данных (запускается отдельно в Coolify)
|
||
- **Prisma ORM** - работа с БД
|
||
- **Socket.IO** - WebSocket сервер
|
||
- **JWT** - авторизация
|
||
- **ConfigModule** - управление переменными окружения
|
||
|
||
## 📁 Структура проекта
|
||
|
||
```
|
||
sto_k_odnomu/
|
||
├── backend/ # NestJS Backend
|
||
│ ├── src/
|
||
│ │ ├── auth/ # Авторизация (JWT, анонимные)
|
||
│ │ ├── rooms/ # Модуль комнат
|
||
│ │ ├── questions/ # Паки вопросов
|
||
│ │ ├── game/ # WebSocket игра
|
||
│ │ ├── stats/ # Статистика
|
||
│ │ └── prisma/ # Prisma сервис
|
||
│ ├── prisma/
|
||
│ │ ├── schema.prisma # Схема БД
|
||
│ │ └── seed.ts # Seed данные
|
||
│
|
||
├── src/ # React Frontend
|
||
│ ├── pages/ # Страницы
|
||
│ │ ├── Home.jsx # Главная
|
||
│ │ ├── CreateRoom.jsx # Создание комнаты
|
||
│ │ ├── JoinRoom.jsx # Присоединение
|
||
│ │ ├── RoomPage.jsx # Лобби комнаты
|
||
│ │ └── GamePage.jsx # Игровая страница
|
||
│ ├── services/ # API & WebSocket
|
||
│ ├── context/ # React Context
|
||
│ ├── hooks/ # Custom hooks
|
||
│ └── components/ # Компоненты игры
|
||
│
|
||
└── PLAN.md # Детальный план разработки
|
||
```
|
||
|
||
## 🚀 Быстрый старт
|
||
|
||
### 1. Backend
|
||
|
||
**Требования:**
|
||
- PostgreSQL должен быть запущен отдельно (например, в Coolify)
|
||
- Переменные окружения должны быть настроены в системе или через Coolify
|
||
|
||
**Переменные окружения:**
|
||
- `DATABASE_URL` - строка подключения к PostgreSQL
|
||
- `JWT_SECRET` - секретный ключ для JWT токенов
|
||
- `PORT` - порт для backend (по умолчанию 3000)
|
||
- `HOST` - хост для backend (по умолчанию 0.0.0.0)
|
||
- `CORS_ORIGIN` - домен frontend приложения, с которого разрешены запросы к backend (по умолчанию http://localhost:5173)
|
||
|
||
**Важно:** `CORS_ORIGIN` - это домен, где работает frontend, а не backend. Например, если frontend на `https://example.com`, а backend на `https://api.example.com`, то `CORS_ORIGIN` должен быть `https://example.com`.
|
||
|
||
```bash
|
||
cd backend
|
||
|
||
# Установить зависимости
|
||
npm install
|
||
|
||
# Выполнить миграции
|
||
npx prisma migrate dev --name init
|
||
|
||
# Заполнить демо-данными (опционально)
|
||
npm run prisma:seed
|
||
|
||
# Запустить backend
|
||
npm run start:dev
|
||
```
|
||
|
||
Backend: http://localhost:3000
|
||
|
||
### 2. Frontend
|
||
|
||
```bash
|
||
# В корне проекта
|
||
npm install
|
||
npm run dev
|
||
```
|
||
|
||
Frontend: http://localhost:5173
|
||
|
||
## 🎯 Как играть
|
||
|
||
### Мультиплеер
|
||
|
||
1. **Главная страница** → Выберите действие
|
||
2. **Создать комнату**:
|
||
- Выберите пак вопросов
|
||
- Настройте параметры
|
||
- Поделитесь кодом/QR с игроками
|
||
3. **Присоединиться**:
|
||
- Введите 6-значный код комнаты
|
||
- Или отсканируйте QR-код
|
||
4. **Начать игру** (ведущий)
|
||
5. Игроки открывают ответы в реальном времени
|
||
|
||
## 📊 API Endpoints
|
||
|
||
### REST API
|
||
|
||
- **Auth**: `/auth/anonymous`, `/auth/register`, `/auth/login`
|
||
- **Rooms**: `/rooms` (POST, GET), `/rooms/:code`, `/rooms/:id/join`
|
||
- **Questions**: `/questions/packs` (CRUD)
|
||
- **Stats**: `/stats/game-history/:userId`, `/stats/user/:userId`
|
||
|
||
### WebSocket Events
|
||
|
||
**Client → Server:**
|
||
- `joinRoom`, `startGame`, `revealAnswer`, `updateScore`, `nextQuestion`, `endGame`
|
||
|
||
**Server → Client:**
|
||
- `roomUpdate`, `gameStarted`, `answerRevealed`, `scoreUpdated`, `questionChanged`, `gameEnded`
|
||
|
||
## 🗄️ База данных
|
||
|
||
### Модели (Prisma)
|
||
|
||
- **User** - пользователи (анонимные/зарегистрированные)
|
||
- **Room** - игровые комнаты
|
||
- **Participant** - участники (HOST/PLAYER/SPECTATOR)
|
||
- **QuestionPack** - паки вопросов
|
||
- **GameHistory** - история игр
|
||
|
||
### Seed данные
|
||
|
||
- Демо пользователь
|
||
- 2 пака вопросов (общие, семейные)
|
||
|
||
## ⚙️ Переменные окружения
|
||
|
||
Приложение использует переменные окружения напрямую через `@nestjs/config`. Все переменные должны быть настроены в системе или через Coolify:
|
||
|
||
### Backend переменные:
|
||
- `DATABASE_URL` - строка подключения к PostgreSQL (например: `postgresql://user:password@host:5432/dbname`)
|
||
- `JWT_SECRET` - секретный ключ для JWT токенов (см. ниже как сгенерировать)
|
||
- `PORT` - порт для backend (по умолчанию 3000)
|
||
- `HOST` - хост для backend (по умолчанию 0.0.0.0)
|
||
- `CORS_ORIGIN` - **домен frontend приложения**, с которого разрешены запросы к backend (по умолчанию http://localhost:5173)
|
||
|
||
**Важно:** `CORS_ORIGIN` - это домен, где работает frontend, а не backend. Это настройка безопасности, которая говорит backend, с каких доменов принимать запросы. Например:
|
||
- Frontend: `https://example.com`
|
||
- Backend: `https://api.example.com`
|
||
- `CORS_ORIGIN` должен быть: `https://example.com`
|
||
|
||
**Поддержка нескольких origins:** Можно указать несколько доменов через запятую:
|
||
```
|
||
CORS_ORIGIN=https://party-games.online,https://www.party-games.online,http://localhost:5173
|
||
```
|
||
|
||
### Frontend переменные:
|
||
- `VITE_API_URL` - URL backend API (по умолчанию http://localhost:3000)
|
||
- `VITE_WS_URL` - URL WebSocket сервера (по умолчанию http://localhost:3000)
|
||
|
||
**Почему префикс `VITE_`?**
|
||
|
||
Vite (инструмент сборки) требует префикс `VITE_` для переменных окружения, которые должны быть доступны в клиентском коде. Это сделано для безопасности — только переменные с этим префиксом встраиваются в собранный JavaScript код.
|
||
|
||
**Как это работает:**
|
||
- В коде используется `import.meta.env.VITE_API_URL` (см. `src/services/api.js`)
|
||
- Vite заменяет эти значения на этапе сборки
|
||
- Без префикса `VITE_` переменная не будет доступна в браузере
|
||
|
||
**Пример использования:**
|
||
```javascript
|
||
// В коде frontend
|
||
const API_URL = import.meta.env.VITE_API_URL || 'http://localhost:3000';
|
||
```
|
||
|
||
**Примечание:** PostgreSQL должен быть запущен отдельно как отдельное приложение в Coolify.
|
||
|
||
### 🔑 Как сгенерировать JWT_SECRET?
|
||
|
||
`JWT_SECRET` - это секретный ключ для подписи и проверки JWT токенов. Он должен быть:
|
||
- **Случайным** и криптографически стойким
|
||
- **Длинным** (минимум 32 символа, рекомендуется 64+)
|
||
- **Уникальным** для каждого приложения
|
||
- **Секретным** - никогда не коммитьте в Git!
|
||
|
||
#### Способы генерации:
|
||
|
||
**1. Используя Node.js:**
|
||
```bash
|
||
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
|
||
```
|
||
|
||
**2. Используя OpenSSL:**
|
||
```bash
|
||
openssl rand -hex 64
|
||
```
|
||
|
||
**3. Используя Python:**
|
||
```bash
|
||
python3 -c "import secrets; print(secrets.token_hex(64))"
|
||
```
|
||
|
||
**4. Онлайн генераторы:**
|
||
- Можно использовать, но не рекомендуется для production
|
||
- Пример: https://generate-secret.vercel.app/64
|
||
|
||
#### Пример сгенерированного ключа:
|
||
```
|
||
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2g3h4i5j6k7l8m9n0o1p2q3r4s5t6u7v8w9x0y1z2
|
||
```
|
||
|
||
#### Где использовать:
|
||
1. **В Coolify**: Добавьте переменную окружения `JWT_SECRET` в настройках приложения
|
||
2. **Локально для разработки**: Можно использовать `.env` файл (но не коммитить его!)
|
||
|
||
**⚠️ ВАЖНО:**
|
||
- Используйте **разные** `JWT_SECRET` для development и production
|
||
- Если измените `JWT_SECRET`, все существующие токены станут недействительными
|
||
- Храните секрет в безопасности - это критически важно для безопасности приложения
|
||
|
||
## 📝 Разработка
|
||
|
||
### Backend
|
||
|
||
```bash
|
||
cd backend
|
||
npm run start:dev # Dev режим
|
||
npm run build # Сборка
|
||
npm run test # Тесты
|
||
npx prisma studio # DB GUI
|
||
```
|
||
|
||
### Frontend
|
||
|
||
```bash
|
||
npm run dev # Dev сервер
|
||
npm run build # Сборка
|
||
npm run preview # Preview build
|
||
```
|
||
|
||
## 🔐 Безопасность
|
||
|
||
- JWT токены для авторизации
|
||
- CORS настройка
|
||
- Валидация данных (class-validator)
|
||
- PostgreSQL для надёжного хранения
|
||
|
||
## 📄 Документация
|
||
|
||
- [Backend README](backend/README.md) - детальная документация backend
|
||
- [PLAN.md](PLAN.md) - полный план разработки
|
||
- [API Documentation](backend/README.md#-api-endpoints) - REST и WebSocket API
|
||
- [TROUBLESHOOTING.md](TROUBLESHOOTING.md) - решение проблем с деплоем (502 ошибки, CORS и т.д.)
|
||
|
||
## 🎨 Особенности
|
||
|
||
- ❄️ Новогодняя анимация снежинок
|
||
- 🎨 Адаптивный дизайн
|
||
- 🔄 Real-time синхронизация
|
||
- 📱 QR-коды для присоединения
|
||
- 📊 Статистика и история игр
|
||
|
||
## 🚧 Roadmap
|
||
|
||
- [x] Backend инфраструктура
|
||
- [x] Frontend интеграция
|
||
- [x] WebSocket real-time
|
||
- [x] Игровые комнаты
|
||
- [x] QR-коды
|
||
- [ ] Таймер ответов
|
||
- [ ] Экспорт статистики (PDF)
|
||
- [ ] Публичные комнаты
|
||
- [ ] Рейтинг игроков
|
||
|
||
## 📜 Лицензия
|
||
|
||
Private project
|
||
|
||
---
|
||
|
||
**Сделано с ❤️ для семейных праздников**
|