12 KiB
100 к 1 - Multiplayer Game
Интерактивная веб-игра "100 к 1" с поддержкой мультиплеера и локальной игры.
🎮 Возможности
🌐 Мультиплеер (NEW!)
- Игровые комнаты с уникальными кодами
- 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 # Лобби комнаты
│ │ └── LocalGame.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.
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
# В корне проекта
npm install
npm run dev
Frontend: http://localhost:5173
🎯 Как играть
Мультиплеер
- Главная страница → Выберите действие
- Создать комнату:
- Выберите пак вопросов
- Настройте параметры
- Поделитесь кодом/QR с игроками
- Присоединиться:
- Введите 6-значный код комнаты
- Или отсканируйте QR-код
- Начать игру (ведущий)
- Игроки открывают ответы в реальном времени
Локальная игра
- Главная → Локальная игра
- Добавьте участников (👥)
- Играйте на одном устройстве
📊 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:
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_переменная не будет доступна в браузере
Пример использования:
// В коде 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:
node -e "console.log(require('crypto').randomBytes(64).toString('hex'))"
2. Используя OpenSSL:
openssl rand -hex 64
3. Используя Python:
python3 -c "import secrets; print(secrets.token_hex(64))"
4. Онлайн генераторы:
- Можно использовать, но не рекомендуется для production
- Пример: https://generate-secret.vercel.app/64
Пример сгенерированного ключа:
a1b2c3d4e5f6g7h8i9j0k1l2m3n4o5p6q7r8s9t0u1v2w3x4y5z6a7b8c9d0e1f2g3h4i5j6k7l8m9n0o1p2q3r4s5t6u7v8w9x0y1z2
Где использовать:
- В Coolify: Добавьте переменную окружения
JWT_SECRETв настройках приложения - Локально для разработки: Можно использовать
.envфайл (но не коммитить его!)
⚠️ ВАЖНО:
- Используйте разные
JWT_SECRETдля development и production - Если измените
JWT_SECRET, все существующие токены станут недействительными - Храните секрет в безопасности - это критически важно для безопасности приложения
📝 Разработка
Backend
cd backend
npm run start:dev # Dev режим
npm run build # Сборка
npm run test # Тесты
npx prisma studio # DB GUI
Frontend
npm run dev # Dev сервер
npm run build # Сборка
npm run preview # Preview build
🔐 Безопасность
- JWT токены для авторизации
- CORS настройка
- Валидация данных (class-validator)
- PostgreSQL для надёжного хранения
📄 Документация
- Backend README - детальная документация backend
- PLAN.md - полный план разработки
- API Documentation - REST и WebSocket API
- TROUBLESHOOTING.md - решение проблем с деплоем (502 ошибки, CORS и т.д.)
🎨 Особенности
- ❄️ Новогодняя анимация снежинок
- 🎨 Адаптивный дизайн
- 💾 Автосохранение прогресса
- 🔄 Real-time синхронизация
- 📱 QR-коды для присоединения
- 📊 Статистика и история игр
🚧 Roadmap
- Backend инфраструктура
- Frontend интеграция
- WebSocket real-time
- Игровые комнаты
- QR-коды
- Таймер ответов
- Экспорт статистики (PDF)
- Публичные комнаты
- Рейтинг игроков
📜 Лицензия
Private project
Сделано с ❤️ для семейных праздников