12 Commits

Author SHA1 Message Date
Donat Magda e634b89b70 save 2025-11-26 01:29:57 +01:00
Donat Magda b39ca0930a Changes 2025-11-26 01:20:57 +01:00
Donat Magda 822254f95e Consolidate to single images tar file 2025-11-26 00:22:20 +01:00
Donat Magda c316db9b32 Remove old deployment tar 2025-11-26 00:18:14 +01:00
Donat Magda d53fe4bb3e Update deployment: fixed backend entities loading and nginx proxy 2025-11-26 00:17:58 +01:00
Donat Magda 1c1792e7e1 fail safe 2025-11-25 23:36:12 +01:00
Donat Magda 0566b58240 Update deployment with working Docker images (730MB) and fixed configuration - Backend now runs successfully with all fixes applied 2025-11-25 23:27:41 +01:00
magdo 88c153eb6a Update deployment with async fixes - prevents unhandled rejections (232.84 MB) 2025-11-25 22:25:41 +01:00
magdo 8c27b5ea2f Fix unhandled promise rejections in LoggingService and WebSocketService - prevent crashes from async operations in constructors 2025-11-25 22:25:09 +01:00
magdo a95ee33123 Add fixed deployment package - backend now properly starts and keeps event loop alive (232.84 MB) 2025-11-25 21:48:25 +01:00
magdo 9653537bc9 Merge fixed backend from main
new file:   SerpentRace_Backend/node_modules/jest-runner/build/testWorker.js
	new file:   SerpentRace_Backend/node_modules/jest/bin/jest.js
	new file:   SerpentRace_Backend/src/Api/index.ts
	new file:   SerpentRace_Backend/src/Application/Services/LoggingService.ts
	new file:   SerpentRace_Backend/tsconfig.json
2025-11-25 21:44:41 +01:00
magdo 4a5486caa4 Fix backend server startup - move listen() inside database init to keep event loop alive 2025-11-25 21:44:08 +01:00
19 changed files with 282 additions and 6051 deletions
-297
View File
@@ -1,297 +0,0 @@
# SerpentRace Backend Build System
## Overview
This document describes the comprehensive build system for the SerpentRace backend application. The build system handles TypeScript compilation, database migrations, asset management, testing, and deployment.
## Quick Start
```bash
# Development build
npm run build
# Production build with full validation
npm run build:production
# Advanced build with migrations and tests
npm run build:advanced:prod
# Development server with hot reload
npm run dev
```
## Build Scripts
### Basic Build Commands
| Command | Description |
|---------|-------------|
| `npm run build` | Standard build: clean → compile → copy assets |
| `npm run build:clean` | Clean the dist directory |
| `npm run build:compile` | Compile TypeScript to JavaScript |
| `npm run build:copy-assets` | Copy non-TS files to dist directory |
| `npm run build:docker` | Build for Docker (no tests/migrations) |
### Production Build Commands
| Command | Description |
|---------|-------------|
| `npm run build:production` | Full production build with linting, tests, and migrations |
| `npm run build:advanced` | Advanced build script with custom options |
| `npm run build:advanced:prod` | Advanced production build with all validations |
| `npm run build:advanced:ci` | CI/CD friendly build (skips linting) |
### Development Commands
| Command | Description |
|---------|-------------|
| `npm run dev` | Start development server with hot reload |
| `npm run watch` | Watch mode TypeScript compilation |
| `npm run typecheck` | Type checking without code generation |
### Database Commands
| Command | Description |
|---------|-------------|
| `npm run migration:run` | Run pending database migrations |
| `npm run migration:show` | Show migration status |
| `npm run migration:generate <name>` | Generate new migration |
| `npm run migration:create <name>` | Create empty migration |
| `npm run migration:revert` | Revert last migration |
| `npm run migration:full <name>` | Create, generate, and run migration |
### Testing Commands
| Command | Description |
|---------|-------------|
| `npm test` | Run all tests |
| `npm run test:watch` | Run tests in watch mode |
| `npm run test:coverage` | Run tests with coverage report |
| `npm run test:redis` | Run Redis-specific tests |
### Deployment Commands
| Command | Description |
|---------|-------------|
| `npm run deploy:prod` | Build for production deployment |
| `scripts/deploy.sh` | Full Linux/Mac deployment script |
| `scripts/deploy.bat` | Full Windows deployment script |
## Advanced Build Script
The advanced build script (`scripts/build.ts`) supports various options:
```bash
# Basic advanced build
npm run build:advanced
# Production build with migrations and tests
npm run build:advanced:prod
# CI/CD build (skips linting, includes tests and migrations)
npm run build:advanced:ci
```
### Build Options
- `--migrations`: Run database migrations during build
- `--test`: Run tests during build
- `--skip-lint`: Skip linting step
- `--production`: Enable production mode (strict validation)
## Deployment Scripts
### Linux/Mac Deployment
```bash
./scripts/deploy.sh [deploy|build-only|test-connections]
```
Options:
- `deploy` (default): Full deployment with validation
- `build-only`: Build without connection testing
- `test-connections`: Test database and Redis connections only
### Windows Deployment
```cmd
scripts\deploy.bat [deploy|build-only|test-connections]
```
Same options as Linux/Mac version.
### Required Environment Variables
The deployment scripts require these environment variables:
```bash
DB_HOST=localhost
DB_PORT=5432
DB_USERNAME=postgres
DB_PASSWORD=your_password
DB_NAME=serpentrace
JWT_SECRET=your_jwt_secret
REDIS_HOST=localhost
REDIS_PORT=6379
```
## Build Process Flow
### Standard Build (`npm run build`)
1. **Clean** - Remove previous build artifacts
2. **Lint** - Code quality checks (if configured)
3. **Compile** - TypeScript compilation
4. **Copy Assets** - Copy non-TS files to dist
5. **Post-build** - Validation and cleanup
### Production Build (`npm run build:production`)
1. **Clean** - Remove previous build artifacts
2. **Lint** - Code quality checks
3. **Test** - Run test suite
4. **Migrations** - Apply database migrations
5. **Compile** - TypeScript compilation
6. **Copy Assets** - Copy non-TS files to dist
7. **Validate** - Ensure build integrity
### Advanced Build (`npm run build:advanced`)
Provides fine-grained control over the build process with comprehensive logging and error handling.
## Asset Management
The build system automatically copies these file types to the dist directory:
- `.json` files (configuration, data)
- `.html` files (templates)
- `.css` files (stylesheets)
- Image files (`.png`, `.jpg`, `.jpeg`, `.gif`, `.svg`, `.ico`)
- Font files (`.woff`, `.woff2`, `.ttf`, `.eot`)
Excluded directories:
- `node_modules`
- `.git`
- `tests`
- `__tests__`
## TypeScript Configuration
The build system uses the following TypeScript settings:
- **Target**: ES2020
- **Module**: CommonJS
- **Output Directory**: `./dist`
- **Source Maps**: Enabled
- **Declarations**: Enabled for type definitions
- **Strict Mode**: Enabled for type safety
## Migration Management
### Creating Migrations
```bash
# Create empty migration
npm run migration:create AddNewTable
# Generate migration from entity changes
npm run migration:generate AddNewTable
# Full migration workflow (create + generate + run)
npm run migration:full AddNewTable
```
### Migration Best Practices
1. Always backup database before running migrations in production
2. Test migrations in development environment first
3. Use descriptive migration names
4. Review generated migrations before running them
## Docker Integration
The build system is optimized for Docker deployments:
```dockerfile
# Use build:docker for container builds
RUN npm run build:docker
# Or use production build for full validation
RUN npm run build:production
```
## Troubleshooting
### Common Issues
1. **Build fails with "Cannot find module"**
- Run `npm ci` to ensure all dependencies are installed
- Check TypeScript paths configuration
2. **Migration errors during build**
- Verify database connection parameters
- Ensure database exists and is accessible
- Check migration files for syntax errors
3. **Asset copying fails**
- Verify file permissions
- Check disk space availability
- Ensure source files exist
4. **TypeScript compilation errors**
- Run `npm run typecheck` for detailed error messages
- Check tsconfig.json configuration
- Verify all type definitions are installed
### Debug Mode
Enable verbose logging by setting the environment variable:
```bash
export DEBUG=serpentrace:*
npm run build:advanced
```
## Performance Optimization
### Build Performance Tips
1. Use `npm ci` instead of `npm install` in CI/CD
2. Enable TypeScript incremental compilation for development
3. Use `--skip-lint` in CI if linting is handled separately
4. Cache node_modules in CI/CD pipelines
### Runtime Performance
The build system optimizes the output for production:
- Source maps for debugging (can be disabled in production)
- Type declarations for library usage
- Compressed and optimized JavaScript output
## Monitoring and Logging
Build logs include:
- Timestamps for each build step
- Error details with stack traces
- Performance metrics (build duration)
- Validation results
Production builds create detailed logs in the `logs/` directory.
## Contributing
When modifying the build system:
1. Test changes with both development and production builds
2. Update this documentation for any new scripts or options
3. Ensure backward compatibility
4. Add appropriate error handling and logging
## Support
For build system issues:
1. Check this documentation
2. Review error logs in the console
3. Verify environment variables are set correctly
4. Test with a clean `node_modules` installation
File diff suppressed because it is too large Load Diff
Binary file not shown.
-392
View File
@@ -1,392 +0,0 @@
# 🗄️ SerpentRace Database Management Guide
## 🎯 Overview
This guide provides comprehensive information about managing all database services in the SerpentRace project, including PostgreSQL, Redis, MinIO, and administration tools.
## 📊 Quick Status Check
### Check All Services
```bash
npm run db:status
```
### Check Individual Services
```bash
npm run db:status:pg # PostgreSQL only
npm run db:status:redis # Redis only
npm run db:status:docker # Docker containers only
```
### Simple Connection Test
```bash
npm run test:connections
```
## 🐘 PostgreSQL Database
### Connection Details
- **Host**: localhost:5432
- **Database**: serpentrace
- **Username**: postgres
- **Password**: postgres
- **Admin Tool**: pgAdmin at http://localhost:8080
### Database Operations
#### Run Migrations
```bash
npm run migration:run
```
#### Create New Migration
```bash
npm run migration:create src/migrations/YourMigrationName
```
#### Generate Migration from Entity Changes
```bash
npm run migration:generate src/migrations/YourMigrationName
```
#### Check Migration Status
```bash
npm run migration:show
```
#### Rollback Last Migration
```bash
npm run migration:revert
```
### Direct Database Access
#### Using psql (if installed)
```bash
psql -h localhost -p 5432 -U postgres -d serpentrace
```
#### Using pgAdmin
1. Open http://localhost:8080
2. Login with: admin@serpentrace.dev / admin
3. Server should be pre-configured as "SerpentRace"
### Common SQL Queries
#### Check Database Size
```sql
SELECT pg_size_pretty(pg_database_size('serpentrace')) as size;
```
#### List All Tables
```sql
SELECT tablename FROM pg_tables WHERE schemaname = 'public';
```
#### Check Active Connections
```sql
SELECT count(*) FROM pg_stat_activity WHERE datname = 'serpentrace';
```
## 🔴 Redis Cache
### Connection Details
- **Host**: localhost:6379
- **No Authentication**: Default Redis setup
- **Admin Tool**: Redis Commander at http://localhost:8081
### Redis Operations
#### Direct Redis Access (if redis-cli installed)
```bash
redis-cli -h localhost -p 6379
```
#### Common Redis Commands
```bash
# Get all keys
KEYS *
# Get key count
DBSIZE
# Check memory usage
INFO memory
# Flush all data (careful!)
FLUSHALL
```
### Using Redis Commander
1. Open http://localhost:8081
2. Browse keys, view data, execute commands
## 🗄️ MinIO Object Storage
### Connection Details
- **Endpoint**: localhost:9000
- **Console**: http://localhost:9001
- **Access Key**: serpentrace
- **Secret Key**: serpentrace123
- **Default Bucket**: serpentrace
### MinIO Operations
#### Access MinIO Console
1. Open http://localhost:9001
2. Login with: serpentrace / serpentrace123
3. Create buckets, upload files, manage storage
#### Health Check
```bash
curl http://localhost:9000/minio/health/live
```
### File Upload Example (Node.js)
```javascript
const Minio = require('minio');
const minioClient = new Minio.Client({
endPoint: 'localhost',
port: 9000,
useSSL: false,
accessKey: 'serpentrace',
secretKey: 'serpentrace123'
});
// Upload file
minioClient.fPutObject('serpentrace', 'test-file.txt', './file.txt');
```
## 🐳 Docker Container Management
### View All Containers
```bash
docker ps -a
```
### View SerpentRace Containers Only
```bash
docker ps -a --filter "name=serpentrace"
```
### Container Operations
#### Restart All Services
```bash
cd d:\munka\SzeSnake\SerpentRace_Docker
docker-compose -f docker-compose.dev.yml restart
```
#### Restart Individual Service
```bash
docker restart serpentrace-postgres-dev # PostgreSQL
docker restart serpentrace-redis-dev # Redis
docker restart serpentrace-minio-dev # MinIO
docker restart serpentrace-pgadmin-dev # pgAdmin
```
#### View Container Logs
```bash
docker logs serpentrace-postgres-dev
docker logs serpentrace-redis-dev -f # Follow logs
```
#### Stop All Services
```bash
cd d:\munka\SzeSnake\SerpentRace_Docker
docker-compose -f docker-compose.dev.yml down
```
#### Start All Services
```bash
cd d:\munka\SzeSnake\SerpentRace_Docker
docker-compose -f docker-compose.dev.yml up -d
```
## 🛠️ Troubleshooting
### PostgreSQL Issues
#### Connection Refused
```bash
# Check if container is running
docker ps | grep postgres
# Check container logs
docker logs serpentrace-postgres-dev
# Restart if needed
docker restart serpentrace-postgres-dev
```
#### Migration Errors
```bash
# Check migration status
npm run migration:show
# Revert last migration if problematic
npm run migration:revert
# Re-run migrations
npm run migration:run
```
### Redis Issues
#### Cannot Connect
```bash
# Check Redis container
docker ps | grep redis
# Test connection
redis-cli -h localhost -p 6379 ping
# Expected response: PONG
```
### MinIO Issues
#### Health Check Failed
```bash
# Check MinIO container
docker ps | grep minio
# Test health endpoint
curl http://localhost:9000/minio/health/live
# Expected response: 200 OK
```
### pgAdmin Issues
#### Cannot Login
- Default credentials: admin@serpentrace.dev / admin
- If issues persist, restart container:
```bash
docker restart serpentrace-pgladmin-dev
```
#### Server Not Found
- pgAdmin should auto-configure the PostgreSQL server
- If not visible, add manually:
- Host: postgres
- Port: 5432
- Database: serpentrace
- Username: postgres
- Password: postgres
## 🔧 Environment Variables
### Default Development Settings
```bash
# PostgreSQL
DB_HOST=localhost
DB_PORT=5432
DB_NAME=serpentrace
DB_USERNAME=postgres
DB_PASSWORD=postgres
# Redis
REDIS_HOST=localhost
REDIS_PORT=6379
# MinIO
MINIO_ENDPOINT=localhost
MINIO_PORT=9000
MINIO_ACCESS_KEY=serpentrace
MINIO_SECRET_KEY=serpentrace123
```
### Production Configuration
Create `.env.production` with secure values:
```bash
DB_HOST=your-production-host
DB_PASSWORD=secure-password
REDIS_PASSWORD=secure-redis-password
MINIO_SECRET_KEY=secure-minio-secret
```
## 📈 Monitoring & Maintenance
### Daily Health Check
```bash
npm run db:status
```
### Weekly Maintenance
```bash
# Check database size growth
npm run db:status:pg
# Review Redis memory usage
npm run db:status:redis
# Clean up old Docker logs
docker system prune
```
### Backup Procedures
#### PostgreSQL Backup
```bash
docker exec serpentrace-postgres-dev pg_dump -U postgres serpentrace > backup.sql
```
#### Redis Backup
```bash
docker exec serpentrace-redis-dev redis-cli BGSAVE
```
#### MinIO Backup
Use MinIO Console or mc client to backup buckets.
## 🎯 Performance Optimization
### PostgreSQL
- Monitor active connections with `npm run db:status:pg`
- Use connection pooling in production
- Regular VACUUM and ANALYZE operations
### Redis
- Monitor memory usage
- Configure appropriate eviction policies
- Use Redis persistence (RDB/AOF) in production
### MinIO
- Configure appropriate bucket policies
- Use lifecycle management for old files
- Monitor storage usage through console
## 🚀 Quick Reference Commands
```bash
# Status and Health
npm run db:status # Full system status
npm run test:connections # Quick connection test
# Database Operations
npm run migration:run # Apply migrations
npm run migration:show # Check migration status
# Docker Management
docker ps # Show running containers
docker logs <container> # View logs
docker restart <container> # Restart service
# Direct Access
psql -h localhost -U postgres -d serpentrace # PostgreSQL CLI
redis-cli -h localhost # Redis CLI
```
## 🌐 Web Interfaces Summary
| Service | URL | Credentials |
|---------|-----|------------|
| pgAdmin | http://localhost:8080 | admin@serpentrace.dev / admin |
| Redis Commander | http://localhost:8081 | No auth required |
| MinIO Console | http://localhost:9001 | serpentrace / serpentrace123 |
| Backend API | http://localhost:3000 | When running |
| Frontend | http://localhost:5173 | When running |
---
*This guide is automatically updated when database configurations change. Last updated: 2025-08-23*
-235
View File
@@ -1,235 +0,0 @@
# Docker Watcher Implementation Guide
## Overview
This document explains the Docker watcher implementation for the SerpentRace project, which automatically synchronizes local file changes with Docker containers and rebuilds images when necessary.
## What's Implemented
### Docker Compose Watch Configuration
The development Docker Compose configuration now includes `develop.watch` sections for both frontend and backend services that provide:
1. **File Synchronization**: Automatically sync source code changes to running containers
2. **Selective Rebuilding**: Rebuild containers when critical configuration files change
3. **Intelligent Ignore Patterns**: Exclude unnecessary files like `node_modules`
### Backend Watcher Configuration
```yaml
develop:
watch:
- action: sync
path: ../SerpentRace_Backend/src
target: /app/src
ignore:
- node_modules/
- action: sync
path: ../SerpentRace_Backend/package.json
target: /app/package.json
- action: rebuild
path: ../SerpentRace_Backend/package-lock.json
- action: rebuild
path: ../SerpentRace_Docker/Dockerfile_backend.dev
```
### Frontend Watcher Configuration
```yaml
develop:
watch:
- action: sync
path: ../SerpentRace_Frontend/src
target: /app/src
ignore:
- node_modules/
- action: sync
path: ../SerpentRace_Frontend/public
target: /app/public
- action: sync
path: ../SerpentRace_Frontend/package.json
target: /app/package.json
- action: rebuild
path: ../SerpentRace_Frontend/package-lock.json
- action: rebuild
path: ../SerpentRace_Frontend/vite.config.js
- action: rebuild
path: ../SerpentRace_Docker/Dockerfile_frontend.dev
```
## How It Works
### Sync Actions
- **Purpose**: Instantly copy changed files from host to container
- **Use Cases**: Source code files, static assets, configuration files that don't require rebuild
- **Performance**: Near-instant updates, no container restart needed
### Rebuild Actions
- **Purpose**: Trigger full container rebuild when critical files change
- **Use Cases**: Package files, Docker configuration, build configuration
- **Performance**: Takes longer but ensures consistency
## Usage
### New Commands Added
#### Windows (docker-manage.bat)
```bash
# Start with file watchers
.\docker-manage.bat dev:watch
# Traditional start (without watchers)
.\docker-manage.bat dev:start
```
#### Linux/Mac (docker-manage.sh)
```bash
# Start with file watchers
./docker-manage.sh dev:watch
# Traditional start (without watchers)
./docker-manage.sh dev:start
```
### Command Differences
| Command | Mode | File Watching | Container Rebuild | Use Case |
|---------|------|---------------|-------------------|----------|
| `dev:start` | Background (-d) | No | Manual only | Traditional development |
| `dev:watch` | Foreground | Yes | Automatic | Modern development with live sync |
## Benefits
### 1. Instant File Synchronization
- Source code changes are immediately available in containers
- No manual rebuild or restart required for code changes
- Maintains all existing hot-reload functionality (nodemon, Vite HMR)
### 2. Smart Rebuilding
- Automatically rebuilds when package.json or Dockerfile changes
- Ensures containers stay consistent with dependency updates
- Prevents common issues with stale dependencies
### 3. Development Efficiency
- Combines Docker's isolation with native-like development speed
- Reduces context switching between local and containerized development
- Maintains consistent environment across team members
## File Patterns Watched
### Backend
- **Synced Files**:
- `src/` directory (all TypeScript source files)
- `package.json` (for runtime reference)
- **Rebuild Triggers**:
- `package-lock.json` (dependency changes)
- `Dockerfile_backend.dev` (container configuration)
### Frontend
- **Synced Files**:
- `src/` directory (React components, styles, etc.)
- `public/` directory (static assets)
- `package.json` (for runtime reference)
- **Rebuild Triggers**:
- `package-lock.json` (dependency changes)
- `vite.config.js` (build configuration)
- `Dockerfile_frontend.dev` (container configuration)
## Performance Considerations
### Sync Performance
- File synchronization is near-instantaneous
- Uses Docker's built-in file watching mechanisms
- Optimized for development workloads
### Rebuild Performance
- Rebuilds only occur when necessary
- Docker layer caching reduces rebuild times
- Can be resource-intensive for large dependency changes
## Troubleshooting
### Common Issues
1. **File Changes Not Reflected**
- Ensure you're using `dev:watch` command
- Check that files are not in ignore patterns
- Verify file paths are correct
2. **Excessive Rebuilds**
- Check for unnecessary changes to rebuild trigger files
- Consider moving files to sync-only patterns if appropriate
3. **Performance Issues**
- Monitor Docker resource usage
- Consider excluding large directories from watching
- Use `.dockerignore` for files that should never be synced
### Debugging Commands
```bash
# Check container status
docker-compose -f SerpentRace_Docker/docker-compose.dev.yml ps
# View watcher logs
docker-compose -f SerpentRace_Docker/docker-compose.dev.yml logs -f backend
docker-compose -f SerpentRace_Docker/docker-compose.dev.yml logs -f frontend
# Check file synchronization
docker exec -it serpentrace-backend-dev ls -la /app/src
docker exec -it serpentrace-frontend-dev ls -la /app/src
```
## Requirements
### Docker Compose Version
- Requires Docker Compose v2.22+ for `develop.watch` support
- Check version: `docker-compose version`
### File System
- Works on Windows, Linux, and macOS
- Performance may vary based on file system type
- WSL2 recommended for Windows users
## Migration from Traditional Setup
### No Breaking Changes
- Existing `dev:start` command continues to work
- All volume mounts remain functional
- Hot reload functionality preserved
### Gradual Adoption
1. Try `dev:watch` for active development
2. Use `dev:start` for background services
3. Gradually migrate team to new workflow
## Best Practices
### Development Workflow
1. Use `dev:watch` during active development
2. Make code changes normally
3. Watch for automatic synchronization
4. Monitor logs for any sync issues
### File Organization
- Keep frequently changed files in sync patterns
- Place build configuration in rebuild patterns
- Use `.dockerignore` for files that should never sync
### Team Collaboration
- Document which command team members should use
- Ensure consistent Docker Compose version across team
- Share troubleshooting steps for common issues
## Future Enhancements
### Potential Improvements
1. **Selective Service Watching**: Watch only specific services
2. **Custom Ignore Patterns**: Per-developer ignore configurations
3. **Performance Monitoring**: Built-in sync performance metrics
4. **Integration with IDEs**: Better editor integration for sync status
### Configuration Expansion
- Additional file patterns as needed
- Service-specific watch configurations
- Environment-based watch rules
@@ -1,570 +0,0 @@
# Frontend Kódolási Útmutató - SerpentRace
## Tartalomjegyzék
1. [Navigáció és Routing](#navigáció-és-routing)
2. [Fájl és Mappa Struktúra](#fájl-és-mappa-struktúra)
3. [Komponens Konvenciók](#komponens-konvenciók)
4. [State Management](#state-management)
5. [API Hívások](#api-hívások)
6. [Hibakezelés](#hibakezelés)
7. [Elnevezési Konvenciók](#elnevezési-konvenciók)
---
## Navigáció és Routing
### ✅ Helyes gyakorlat: HandleNavigate használata
**MINDIG használd a központosított HandleNavigate hook-ot navigációhoz:**
```jsx
import HandleNavigate from "../../utils/HandleNavigate/HandleNavigate"
const MyComponent = () => {
const { goHome, goLogin, goDeckDetails } = HandleNavigate()
const handleClick = () => {
goHome() // Egyszerű navigáció
}
const handleDeckView = (deckId) => {
goDeckDetails(deckId) // Dinamikus route paraméterrel
}
const handleLobby = (gameCode) => {
goLobby({ gameCode }) // State passzolással
}
}
```
### ❌ Kerülendő: Direkt useNavigate használat
```jsx
// SOHA NE HASZNÁLD EZT!
import { useNavigate } from "react-router-dom"
const MyComponent = () => {
const navigate = useNavigate()
navigate("/home") // ❌ NEM JÓ!
}
```
### Elérhető Navigációs Függvények
**HandleNavigate által biztosított függvények:**
```jsx
const {
// Általános
goTo, // goTo('/any-path', { state: {...} })
goBack, // Vissza az előző oldalra
// Authentikáció
goHome, // → /home
goLogin, // → /login, state: { success, message }
goRegister, // → /register (alias: goAuth)
goLanding, // → / (landing page)
// Deck Management
goDecks, // → /decks
goDeckDetails, // goDeckDetails(deckId) → /deck/:deckId
goDeckCreator, // → /deck-creator
goDeckCreatorEdit, // goDeckCreatorEdit(deckId) → /deck-creator/:deckId
// Game Flow
goLobby, // goLobby({ gameCode }) → /lobby
goChooseDeck, // goChooseDeck({ username, deckIds }) → /choosedeck
goPlayerSetup, // goPlayerSetup({ deckIds }) → /player-setup
goGame, // goGame({ players, gameState }) → /game
// Egyéb
goContacts // → /contacts (alias: goCompanies)
} = HandleNavigate()
```
### Route Konstansok
**Használd a centralizált route konstansokat:**
```jsx
// src/utils/routes.js
import { ROUTES } from '../../utils/routes'
// App.jsx-ben
<Route path={ROUTES.HOME} element={<Home />} />
<Route path={ROUTES.DECK_DETAILS} element={<DeckDetails />} />
// ❌ NE használj string literálokat:
<Route path="/home" element={<Home />} /> // NEM JÓ!
```
### State Passzolás
**Így adj át adatokat navigáció során:**
```jsx
// Régi mód (useNavigate) - ❌ NE!
navigate('/lobby', { state: { gameCode: 'ABC123' } })
// Új mód (HandleNavigate) - ✅ JÓ!
goLobby({ gameCode: 'ABC123' })
// Fogadó oldalon:
import { useLocation } from 'react-router-dom'
const Lobby = () => {
const location = useLocation()
const gameCode = location.state?.gameCode
}
```
---
## Fájl és Mappa Struktúra
### Mappa Szervezés
```
src/
├── api/ # API hívások
│ ├── userApi.js
│ ├── deckApi.js
│ └── gameApi.js
├── assets/ # Statikus fájlok
│ ├── backgrounds/
│ ├── images/
│ └── icons/
├── components/ # Újrahasználható komponensek
│ ├── Buttons/
│ ├── Inputs/
│ ├── Navbar/
│ └── PopUp/
├── hooks/ # Custom Hooks
│ └── useRequireAuth.jsx
├── pages/ # Oldal komponensek
│ ├── Auth/
│ ├── Game/
│ ├── Decks/
│ └── Landing/
├── utils/ # Utility függvények
│ ├── HandleNavigate/
│ └── routes.js
└── App.jsx # Fő alkalmazás komponens
```
### Fájl Elnevezési Konvenciók
- **Komponensek**: PascalCase
- `LoginForm.jsx`, `DeckCreator.jsx`, `ButtonGreen.jsx`
- **Utility fájlok**: camelCase
- `routes.js`, `randomUtils.js`, `userApi.js`
- **Hook fájlok**: camelCase, "use" prefix
- `useRequireAuth.jsx`, `useLocalStorage.jsx`
---
## Komponens Konvenciók
### Funkcionális Komponens Sablon
```jsx
import React, { useState, useEffect } from 'react'
import HandleNavigate from '../../utils/HandleNavigate/HandleNavigate'
/**
* Komponens rövid leírása
* @returns {JSX.Element}
*/
const MyComponent = () => {
// 1. Hooks (HandleNavigate, useState, useEffect, stb.)
const { goHome } = HandleNavigate()
const [data, setData] = useState(null)
// 2. Effect hooks
useEffect(() => {
// Component mount logic
}, [])
// 3. Event handlers
const handleClick = () => {
// Logic
}
// 4. Render
return (
<div>
{/* JSX */}
</div>
)
}
export default MyComponent
```
### Import Sorrend
```jsx
// 1. React és third-party library-k
import React, { useState } from 'react'
import { motion } from 'framer-motion'
// 2. React Router hooks (useLocation, useParams - NEM useNavigate!)
import { useLocation } from 'react-router-dom'
// 3. Custom hooks és utils
import HandleNavigate from '../../utils/HandleNavigate/HandleNavigate'
import useRequireAuth from '../../hooks/useRequireAuth'
// 4. API
import { getUserData } from '../../api/userApi'
// 5. Komponensek
import Button from '../../components/Buttons/Button'
import Navbar from '../../components/Navbar/Navbar'
// 6. Assets
import Background from '../../assets/backgrounds/Background'
```
---
## State Management
### Local State
```jsx
// Egyszerű state
const [count, setCount] = useState(0)
// Object state
const [user, setUser] = useState({
name: '',
email: ''
})
// Array state
const [items, setItems] = useState([])
```
### LocalStorage Használat
**useRequireAuth hook használata auth kezeléshez:**
```jsx
import useRequireAuth from '../../hooks/useRequireAuth'
const MyComponent = () => {
const [username] = useRequireAuth({
key: 'username',
redirectTo: '/login'
})
// username automatikusan szinkronizálva van localStorage-el
// Ha nincs username, automatikus redirect /login-re
}
```
**Manuális localStorage:**
```jsx
// Írás
localStorage.setItem('gameToken', token)
// Olvasás
const token = localStorage.getItem('gameToken')
// Törlés
localStorage.removeItem('gameToken')
```
---
## API Hívások
### API File Struktúra
**Minden API endpoint egy külön file-ban (`userApi.js`, `deckApi.js`, `gameApi.js`):**
```jsx
// src/api/userApi.js
import axiosInstance from './axiosInstance'
export const getUserData = async (userId) => {
try {
const response = await axiosInstance.get(`/users/${userId}`)
return response.data
} catch (error) {
console.error('Error fetching user data:', error)
throw error
}
}
export const updateUser = async (userId, userData) => {
try {
const response = await axiosInstance.put(`/users/${userId}`, userData)
return response.data
} catch (error) {
console.error('Error updating user:', error)
throw error
}
}
```
### API Hívás Komponensben
```jsx
import { getUserData } from '../../api/userApi'
const MyComponent = () => {
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [data, setData] = useState(null)
const fetchData = async () => {
setLoading(true)
setError(null)
try {
const result = await getUserData(userId)
setData(result)
} catch (err) {
setError(err.message || 'Hiba történt')
} finally {
setLoading(false)
}
}
useEffect(() => {
fetchData()
}, [userId])
if (loading) return <div>Betöltés...</div>
if (error) return <div>Hiba: {error}</div>
return <div>{/* data megjelenítése */}</div>
}
```
---
## Hibakezelés
### Try-Catch Blokkok
```jsx
const handleSubmit = async () => {
try {
const response = await createDeck(deckData)
// Siker kezelése
notifySuccess('Deck sikeresen létrehozva!')
goDecks()
} catch (error) {
// Hiba kezelése
const errorMessage = error.response?.data?.message || 'Ismeretlen hiba'
setError(errorMessage)
notifyError(errorMessage)
}
}
```
### Toast Notifications
```jsx
import { notifySuccess, notifyError } from '../../components/Toastify/toastifyServices'
// Siker üzenet
notifySuccess('✅ Művelet sikeres!')
// Hiba üzenet
notifyError('❌ Hiba történt!')
// Egyedi konfiguráció
notifySuccess('Mentve!', { autoClose: 2000 })
```
---
## Elnevezési Konvenciók
### JavaScript/React
| Típus | Konvenció | Példa |
|-------|-----------|-------|
| Komponensek | PascalCase | `LoginForm`, `DeckCreator` |
| Függvények | camelCase | `handleClick`, `fetchUserData` |
| Változók | camelCase | `userName`, `isLoading` |
| Konstansok | UPPER_SNAKE_CASE | `API_BASE_URL`, `MAX_PLAYERS` |
| Private változók | _camelCase | `_internalState` |
| Event handlers | handle + PascalCase | `handleSubmit`, `handleInputChange` |
| Boolean változók | is/has/can prefix | `isLoading`, `hasError`, `canEdit` |
### CSS Classes (Tailwind)
```jsx
// Használj explicit class neveket
<div className="flex items-center justify-between p-4 bg-white rounded-lg shadow-md">
// Kerüld a túl hosszú class stringeket - bontsd több sorra
<div
className="
flex items-center justify-between
p-4 bg-white rounded-lg shadow-md
hover:shadow-lg transition-shadow duration-200
"
>
```
### Fájl Nevek
- **Egyedi komponens**: `LoginForm.jsx` (nem `login-form.jsx`)
- **Index fájlok**: `index.jsx` (ha könyvtárban több file van)
- **Utility fájlok**: `randomUtils.js` (camelCase)
- **API fájlok**: `userApi.js` (camelCase + Api postfix)
---
## Teljes Példa - Best Practices
```jsx
// src/pages/Example/ExamplePage.jsx
import React, { useState, useEffect } from 'react'
import { useLocation } from 'react-router-dom'
import { motion } from 'framer-motion'
import HandleNavigate from '../../utils/HandleNavigate/HandleNavigate'
import useRequireAuth from '../../hooks/useRequireAuth'
import { fetchExampleData, updateExampleData } from '../../api/exampleApi'
import { notifySuccess, notifyError } from '../../components/Toastify/toastifyServices'
import Navbar from '../../components/Navbar/Navbar'
import Button from '../../components/Buttons/Button'
import Background from '../../assets/backgrounds/Background'
/**
* Example Page - Komponens rövid leírása
* @returns {JSX.Element}
*/
const ExamplePage = () => {
// 1. Auth & Navigation
const [username] = useRequireAuth({ key: 'username', redirectTo: '/login' })
const { goHome, goBack } = HandleNavigate()
const location = useLocation()
// 2. State
const [data, setData] = useState(null)
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
// 3. Effects
useEffect(() => {
loadData()
}, [])
// 4. Functions
const loadData = async () => {
setLoading(true)
setError(null)
try {
const result = await fetchExampleData()
setData(result)
} catch (err) {
const errorMsg = err.response?.data?.message || 'Hiba történt'
setError(errorMsg)
notifyError(errorMsg)
} finally {
setLoading(false)
}
}
const handleSave = async () => {
try {
await updateExampleData(data)
notifySuccess('✅ Sikeresen mentve!')
goHome()
} catch (err) {
notifyError('❌ Mentés sikertelen')
}
}
const handleCancel = () => {
goBack()
}
// 5. Conditional Rendering
if (loading) {
return (
<div className="flex items-center justify-center min-h-screen">
<div>Betöltés...</div>
</div>
)
}
if (error) {
return (
<div className="flex items-center justify-center min-h-screen">
<div className="text-red-500">Hiba: {error}</div>
</div>
)
}
// 6. Main Render
return (
<div className="min-h-screen bg-gray-100">
<Background />
<Navbar />
<main className="container mx-auto px-4 py-8">
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
<h1 className="text-3xl font-bold mb-6">Example Page</h1>
{/* Content */}
<div className="bg-white rounded-lg shadow-md p-6">
{data && (
<div>
{/* Render data */}
</div>
)}
</div>
{/* Actions */}
<div className="flex gap-4 mt-6">
<Button onClick={handleSave} text="Mentés" />
<Button onClick={handleCancel} text="Mégse" variant="secondary" />
</div>
</motion.div>
</main>
</div>
)
}
export default ExamplePage
```
---
## Összefoglalás - Legfontosabb Szabályok
1.**MINDIG használd HandleNavigate-et** navigációhoz
2.**Használd a ROUTES konstansokat** az App.jsx-ben
3.**API hívások külön file-okban** (userApi.js, deckApi.js, stb.)
4.**Try-catch minden async műveletnél**
5.**Toast notifications** a felhasználói visszajelzéshez
6.**useRequireAuth hook** auth védett oldalaknál
7.**Konzisztens import sorrend**
8.**PascalCase komponenseknek, camelCase változóknak**
9.**SOHA ne használj useNavigate közvetlen**
10.**Ne használj string literal route-okat**
---
**Verzió:** 1.0
**Utolsó frissítés:** 2025-01-17
**Készítette:** SerpentRace Development Team
-476
View File
@@ -1,476 +0,0 @@
# Frontend Game Completion Implementation
**Date:** November 19, 2025
**Status:** ✅ Core gameplay event handlers and action methods implemented
---
## Overview
This document details the completion of missing WebSocket event handlers and action methods in the frontend to enable full gameplay functionality. The implementation ensures that GameScreen can properly receive and respond to all game events from the backend.
---
## Changes Implemented
### 1. GameWebSocketContext.jsx - Added Missing Event Handlers
**Location:** `SerpentRace_Frontend/src/contexts/GameWebSocketContext.jsx`
Added 9 critical gameplay event handlers that were missing from the context:
#### ✅ game:your-turn
- **Purpose:** Notifies player when it's their turn
- **Action:** Updates currentTurn state, emits custom event for GameScreen
- **Implementation:**
```javascript
socket.on('game:your-turn', (data) => {
log('🎯 Your turn!', data);
setCurrentTurn(data.currentPlayer);
window.dispatchEvent(new CustomEvent('game:your-turn', { detail: data }));
});
```
#### ✅ game:dice-rolled
- **Purpose:** Broadcasts dice roll results to all players
- **Action:** Emits custom event for UI to display dice animation
- **Implementation:**
```javascript
socket.on('game:dice-rolled', (data) => {
log('🎲 Dice rolled:', data.diceValue, 'by', data.playerName);
window.dispatchEvent(new CustomEvent('game:dice-rolled', { detail: data }));
});
```
#### ✅ game:guess-result
- **Purpose:** Receives position guess validation result
- **Action:** Updates player position if guess was correct, emits event
- **Implementation:**
```javascript
socket.on('game:guess-result', (data) => {
log('🎯 Guess result:', data);
if (data.correct && data.newPosition !== undefined) {
setBoardData(prev => {
if (!prev) return prev;
const updatedPlayers = { ...prev.playerPositions };
updatedPlayers[data.playerName] = data.newPosition;
return { ...prev, playerPositions: updatedPlayers };
});
}
window.dispatchEvent(new CustomEvent('game:guess-result', { detail: data }));
});
```
#### ✅ game:joker-complete
- **Purpose:** Receives joker card approval/rejection result
- **Action:** Updates player position if joker was approved, emits event
- **Implementation:**
```javascript
socket.on('game:joker-complete', (data) => {
log('🃏 Joker complete:', data);
if (data.approved && data.newPosition !== undefined) {
setBoardData(prev => {
if (!prev) return prev;
const updatedPlayers = { ...prev.playerPositions };
updatedPlayers[data.playerName] = data.newPosition;
return { ...prev, playerPositions: updatedPlayers };
});
}
window.dispatchEvent(new CustomEvent('game:joker-complete', { detail: data }));
});
```
#### ✅ game:luck-consequence
- **Purpose:** Receives luck card consequence (extra turns, lost turns, position changes)
- **Action:** Updates player position if consequence includes movement, emits event
- **Implementation:**
```javascript
socket.on('game:luck-consequence', (data) => {
log('🍀 Luck consequence:', data);
if (data.newPosition !== undefined && data.playerName) {
setBoardData(prev => {
if (!prev) return prev;
const updatedPlayers = { ...prev.playerPositions };
updatedPlayers[data.playerName] = data.newPosition;
return { ...prev, playerPositions: updatedPlayers };
});
}
window.dispatchEvent(new CustomEvent('game:luck-consequence', { detail: data }));
});
```
#### ✅ game:ended
- **Purpose:** Announces game end with winner and final scores
- **Action:** Updates gameState with winner and final scores, emits event for winner modal
- **Implementation:**
```javascript
socket.on('game:ended', (data) => {
log('🏁 Game ended! Winner:', data.winner);
setGameState(prev => ({
...prev,
status: 'finished',
winner: data.winner,
finalScores: data.scores
}));
window.dispatchEvent(new CustomEvent('game:ended', { detail: data }));
});
```
#### ✅ game:extra-turn-remaining
- **Purpose:** Notifies player they have extra turn(s) from luck consequences
- **Action:** Emits event for UI notification
- **Implementation:**
```javascript
socket.on('game:extra-turn-remaining', (data) => {
log('⭐ Extra turn remaining:', data);
window.dispatchEvent(new CustomEvent('game:extra-turn-remaining', { detail: data }));
});
```
#### ✅ game:players-skipped
- **Purpose:** Broadcasts when players are skipped due to lost turn consequences
- **Action:** Emits event for UI notification
- **Implementation:**
```javascript
socket.on('game:players-skipped', (data) => {
log('⏭️ Players skipped:', data.skippedPlayers);
window.dispatchEvent(new CustomEvent('game:players-skipped', { detail: data }));
});
```
#### ✅ game:cleanup-complete
- **Purpose:** Confirms cleanup after game end
- **Action:** Emits event for final UI state reset
- **Implementation:**
```javascript
socket.on('game:cleanup-complete', (data) => {
log('🧹 Cleanup complete:', data);
window.dispatchEvent(new CustomEvent('game:cleanup-complete', { detail: data }));
});
```
---
### 2. GameWebSocketContext.jsx - Added Missing Action Methods
Added 4 critical action methods that players and gamemaster need:
#### ✅ submitAnswer(answer)
- **Purpose:** Submit answer to question card
- **Parameters:** `answer` - Player's answer (type depends on card type: string for QUIZ/OWN_ANSWER, array for SENTENCE_PAIRING, boolean for TRUE_FALSE, number for CLOSER)
- **Emits:** `game:card-answer` with gameCode and answer
- **Returns:** Boolean (success/failure)
```javascript
const submitAnswer = useCallback((answer) => {
const socket = socketRef.current;
if (!socket || !isConnected) {
warn('⚠️ Cannot submit answer: not connected');
return false;
}
log('📝 Submitting answer:', answer);
socket.emit('game:card-answer', { gameCode: gameState?.gameCode, answer });
return true;
}, [isConnected, gameState?.gameCode]);
```
#### ✅ submitPositionGuess(guessedPosition)
- **Purpose:** Submit position guess after correct answer
- **Parameters:** `guessedPosition` - Number (0-99) representing guessed board position
- **Emits:** `game:position-guess` with gameCode and guessedPosition
- **Returns:** Boolean (success/failure)
```javascript
const submitPositionGuess = useCallback((guessedPosition) => {
const socket = socketRef.current;
if (!socket || !isConnected) {
warn('⚠️ Cannot submit position guess: not connected');
return false;
}
log('🎯 Submitting position guess:', guessedPosition);
socket.emit('game:position-guess', { gameCode: gameState?.gameCode, guessedPosition });
return true;
}, [isConnected, gameState?.gameCode]);
```
#### ✅ approveJoker(requestId)
- **Purpose:** Gamemaster approves joker card
- **Parameters:** `requestId` - Unique identifier for joker decision request
- **Emits:** `game:gamemaster-decision` with gameCode, requestId, decision: 'approve'
- **Returns:** Boolean (success/failure)
- **Authorization:** Requires isGamemaster = true
```javascript
const approveJoker = useCallback((requestId) => {
const socket = socketRef.current;
if (!socket || !isConnected || !isGamemaster) {
warn('⚠️ Cannot approve joker: not gamemaster or not connected');
return false;
}
log('✅ Approving joker request:', requestId);
socket.emit('game:gamemaster-decision', {
gameCode: gameState?.gameCode,
requestId,
decision: 'approve'
});
return true;
}, [isConnected, isGamemaster, gameState?.gameCode]);
```
#### ✅ rejectJoker(requestId, reason?)
- **Purpose:** Gamemaster rejects joker card
- **Parameters:**
- `requestId` - Unique identifier for joker decision request
- `reason` - Optional rejection reason (default: 'Joker answer rejected')
- **Emits:** `game:gamemaster-decision` with gameCode, requestId, decision: 'reject', reason
- **Returns:** Boolean (success/failure)
- **Authorization:** Requires isGamemaster = true
```javascript
const rejectJoker = useCallback((requestId, reason = 'Joker answer rejected') => {
const socket = socketRef.current;
if (!socket || !isConnected || !isGamemaster) {
warn('⚠️ Cannot reject joker: not gamemaster or not connected');
return false;
}
log('❌ Rejecting joker request:', requestId, 'Reason:', reason);
socket.emit('game:gamemaster-decision', {
gameCode: gameState?.gameCode,
requestId,
decision: 'reject',
reason
});
return true;
}, [isConnected, isGamemaster, gameState?.gameCode]);
```
---
### 3. GameWebSocketContext.jsx - Updated Context Value Export
Updated the context value to export all new methods:
```javascript
const value = {
socket: socketRef.current,
isConnected,
gameState,
players,
boardData,
currentTurn,
error,
isGamemaster,
gameStarted,
pendingPlayers,
approvalStatus,
// Connection management
connect,
disconnect,
// Methods
rollDice,
sendMessage,
setReady,
leaveGame,
approvePlayer,
rejectPlayer,
submitAnswer, // ✅ NEW
submitPositionGuess, // ✅ NEW
approveJoker, // ✅ NEW
rejectJoker, // ✅ NEW
addEventListener,
removeEventListener,
};
```
---
### 4. GameScreen.jsx - Fixed Action Method Calls
**Location:** `SerpentRace_Frontend/src/pages/Game/GameScreen.jsx`
#### Fixed handleSubmitAnswer
**Before:**
```javascript
const handleSubmitAnswer = useCallback((answer) => {
if (currentCard?.id) {
submitAnswer(currentCard.id, answer) // ❌ Wrong parameters
}
}, [currentCard?.id, submitAnswer])
```
**After:**
```javascript
const handleSubmitAnswer = useCallback((answer) => {
console.log('📝 Válasz beküldve:', answer)
submitAnswer(answer) // ✅ Correct - backend extracts gameCode from context
}, [submitAnswer])
```
#### Fixed handleApproveJoker
**Before:**
```javascript
const handleApproveJoker = useCallback(async (jokerRequest) => {
approveJoker(jokerRequest.playerId, jokerRequest.cardId, jokerRequest.requestId) // ❌ Wrong parameters
setIsJokerModalOpen(false)
}, [approveJoker])
```
**After:**
```javascript
const handleApproveJoker = useCallback(async (jokerRequest) => {
console.log('✅ Joker feladat jóváhagyva:', jokerRequest)
approveJoker(jokerRequest.requestId) // ✅ Correct - only requestId needed
setIsJokerModalOpen(false)
}, [approveJoker])
```
#### Fixed handleRejectJoker
**Before:**
```javascript
const handleRejectJoker = useCallback(async (jokerRequest) => {
rejectJoker(jokerRequest.playerId, jokerRequest.cardId, jokerRequest.requestId) // ❌ Wrong parameters
setIsJokerModalOpen(false)
}, [rejectJoker])
```
**After:**
```javascript
const handleRejectJoker = useCallback(async (jokerRequest) => {
console.log('❌ Joker feladat elutasítva:', jokerRequest)
rejectJoker(jokerRequest.requestId, 'Joker rejected by gamemaster') // ✅ Correct
setIsJokerModalOpen(false)
}, [rejectJoker])
```
---
## Architecture Benefits
### ✅ Centralized Event Handling
All WebSocket events are handled in the context, ensuring:
- Single source of truth for game state
- Consistent state updates across all components
- Easy debugging with centralized logging
### ✅ Custom Event Bridge
Events are re-emitted as CustomEvents via `window.dispatchEvent()`, allowing:
- GameScreen to add specific UI logic without modifying context
- Separation of concerns (state management vs UI presentation)
- Multiple components can listen to the same events independently
### ✅ Persistent Connection
Socket connection persists across navigation (Lobby → GameScreen), ensuring:
- No disconnections during page transitions
- Gamemaster can start game without socket dropping
- Real-time updates continue seamlessly
### ✅ Type Safety & Validation
All action methods include:
- Connection state checks (`isConnected`)
- Authorization checks (`isGamemaster` for approval methods)
- Error logging for debugging
- Boolean return values for success/failure
---
## Testing Checklist
### ✅ Event Handler Tests
- [ ] Test `game:your-turn` - Turn indicator updates
- [ ] Test `game:dice-rolled` - Dice animation triggers
- [ ] Test `game:guess-result` - Position updates on correct guess
- [ ] Test `game:joker-complete` - Position updates on approved joker
- [ ] Test `game:luck-consequence` - Position updates from luck cards
- [ ] Test `game:ended` - Winner modal displays with final scores
- [ ] Test `game:extra-turn-remaining` - Extra turn notification
- [ ] Test `game:players-skipped` - Skip notification
- [ ] Test `game:cleanup-complete` - Cleanup confirmation
### ✅ Action Method Tests
- [ ] Test `submitAnswer()` - Answer submission for all card types (QUIZ, SENTENCE_PAIRING, TRUE_FALSE, CLOSER, OWN_ANSWER)
- [ ] Test `submitPositionGuess()` - Position guess submission
- [ ] Test `approveJoker()` - Gamemaster approval (requires isGamemaster)
- [ ] Test `rejectJoker()` - Gamemaster rejection (requires isGamemaster)
### ✅ Integration Tests
- [ ] Complete game flow: Start → Dice → Card → Answer → Position Guess → Next Turn
- [ ] Joker flow: Joker drawn → Request sent → Gamemaster decision → Position update
- [ ] Luck flow: Luck card → Consequence applied → Position/turn updated
- [ ] End game flow: Player reaches finish → Winner announced → Scores displayed
---
## Remaining UI Enhancements
### 🎨 Turn Indicator Component
**Status:** Not implemented
**Description:** Visual indicator showing whose turn it is
**Events:** `game:your-turn`, `game:turn-changed`
**Location:** GameScreen.jsx header area
### ⏱️ Timer Component
**Status:** Not implemented
**Description:** Countdown timer for card answers (60s) and joker decisions (120s)
**Events:** `game:card-drawn-self`, `game:gamemaster-decision-request`
**Location:** CardDisplayModal, JokerApprovalModal
### 🏆 Winner Modal
**Status:** Not implemented
**Description:** Full-screen modal showing winner, final scores, and play again option
**Events:** `game:ended`
**Location:** GameScreen.jsx (new modal component)
### ✨ Position Update Animations
**Status:** Not implemented
**Description:** Smooth token movement animations for position changes
**Events:** `game:player-moved`, `game:guess-result`, `game:joker-complete`, `game:luck-consequence`
**Location:** GameScreen.jsx player token rendering
### 📊 Score Display
**Status:** Not implemented
**Description:** Live leaderboard showing player rankings
**State:** `players` array with position data
**Location:** GameScreen.jsx sidebar or header
---
## Known Issues & Future Work
### 🐛 Known Issues
None currently - all core functionality implemented and error-free.
### 🚀 Future Enhancements
1. **Notification System** - Toast/notification UI for game events
2. **Sound Effects** - Audio feedback for dice, cards, turns
3. **Animation Polish** - Smooth transitions for all state changes
4. **Mobile Responsiveness** - Touch-friendly controls for mobile devices
5. **Accessibility** - ARIA labels, keyboard navigation, screen reader support
6. **Reconnection Logic** - Handle network interruptions gracefully
7. **Spectator Mode** - Allow non-playing users to watch games
8. **Chat System** - Player communication during game
---
## Summary
**9 critical event handlers** added to GameWebSocketContext
**4 essential action methods** added to GameWebSocketContext
**3 handler fixes** in GameScreen for correct parameter usage
**Zero compilation errors** - all changes validated
**Full gameplay flow** now supported by frontend
The frontend is now **functionally complete** for core gameplay. Players can:
- Receive turn notifications
- Roll dice and move
- Draw and answer cards
- Submit position guesses
- Complete joker challenges (with gamemaster approval)
- Experience luck consequences
- See game end with winner announcement
Remaining work is **UI polish** (animations, timers, winner screen) rather than functional gaps.
---
**Last Updated:** November 19, 2025
**Next Steps:** Implement UI enhancements and run comprehensive integration tests.
File diff suppressed because it is too large Load Diff
-117
View File
@@ -1,117 +0,0 @@
# pgAdmin Database Administration Guide
## Access pgAdmin
- **URL**: http://localhost:8080
- **Email**: admin@serpentrace.dev
- **Password**: admin
## Pre-configured Server
The pgAdmin interface should have a pre-configured server named **"SerpentRace PostgreSQL Dev"** in the "Development" group.
## Manual Server Configuration (If Needed)
If the server is not automatically configured, add it manually:
### Server Details
- **Name**: SerpentRace PostgreSQL Dev
- **Host**: postgres (or localhost if connecting from outside Docker)
- **Port**: 5432
- **Database**: serpentrace
- **Username**: postgres
- **Password**: postgres
### Steps to Add Server Manually
1. Right-click on "Servers" in the left panel
2. Select "Register" > "Server..."
3. Fill in the "General" tab:
- Name: `SerpentRace PostgreSQL Dev`
- Server group: `Development`
4. Fill in the "Connection" tab:
- Host name/address: `postgres`
- Port: `5432`
- Maintenance database: `serpentrace`
- Username: `postgres`
- Password: `postgres`
5. Click "Save"
## Common Database Operations
### View Tables
1. Expand the server connection
2. Expand "Databases" > "serpentrace"
3. Expand "Schemas" > "public"
4. Expand "Tables"
### Run SQL Queries
1. Right-click on the database name
2. Select "Query Tool"
3. Write your SQL queries in the editor
4. Click the "Execute" button or press F5
### View Data
1. Right-click on any table
2. Select "View/Edit Data" > "All Rows"
## Troubleshooting
### Connection Issues
- Ensure Docker containers are running: `docker ps`
- Check container logs: `docker logs serpentrace-postgres-dev`
- Test connections: `npm run test:connections`
### Authentication Failed
- Verify the password is correct: `postgres`
- Check if you're using the correct hostname: `postgres` (inside Docker) vs `localhost` (outside Docker)
### Server Not Appearing
- Restart pgAdmin container:
```bash
docker-compose -f docker-compose.dev.yml restart pgadmin
```
- Clear browser cache and reload
## Development Tips
### Useful SQL Queries
```sql
-- List all tables
SELECT table_name FROM information_schema.tables
WHERE table_schema = 'public';
-- Check database size
SELECT pg_size_pretty(pg_database_size('serpentrace'));
-- View active connections
SELECT * FROM pg_stat_activity WHERE datname = 'serpentrace';
-- Check migration status (if using TypeORM)
SELECT * FROM migrations ORDER BY timestamp DESC;
```
### Database Backup
1. Right-click on database name
2. Select "Backup..."
3. Choose format (Custom recommended for pgAdmin restore)
4. Set filename and location
5. Click "Backup"
### Database Restore
1. Right-click on "Databases"
2. Select "Restore..."
3. Choose the backup file
4. Configure options as needed
5. Click "Restore"
## Security Notes
⚠️ **Development Only**: The current configuration uses default credentials and is intended for development only. For production:
- Use strong, unique passwords
- Enable SSL connections
- Restrict network access
- Use environment variables for credentials
- Enable authentication and authorization features
+8 -7
View File
@@ -28,12 +28,12 @@ JWT_REFRESH_EXPIRATION=7d
# Email Configuration (SMTP)
# CHANGE THESE: Configure your email provider
EMAIL_HOST=smtp.yourmailprovider.com
EMAIL_PORT=587
EMAIL_SECURE=false
EMAIL_USER=your_email@yourdomain.com
EMAIL_PASS=your_email_password
EMAIL_FROM="SerpentRace <noreply@yourdomain.com>"
EMAIL_HOST=mail.serpentrace.hu
EMAIL_PORT=465
EMAIL_SECURE=true
EMAIL_USER=noreply@serpentrace.hu
EMAIL_PASS=ZUx720ece&Cin&F{
EMAIL_FROM="SerpentRace <noreply@serpentrace.hu>"
# MinIO Object Storage
MINIO_ENDPOINT=minio
@@ -45,7 +45,8 @@ MINIO_SECRET_KEY=CHANGE_THIS_MINIO_SECRET_KEY_123!
MINIO_BUCKET_NAME=serpentrace-logs
# Application Settings
APP_BASE_URL=http://your-domain.com
APP_BASE_URL=https://szesnake.ddc.sze.hu
FRONTEND_URL=https://szesnake.ddc.sze.hu
PORT=3000
# Chat System Limits
+8
View File
@@ -201,3 +201,11 @@ docker-compose -f docker-compose.deploy.yml up -d
- Redis: 7-alpine
- MinIO: Latest
- Nginx: Alpine
## DataBase information
- System: PostgreSQL
- Server: postgres
- Username: postgres
- Password: postgres
- Database: serpentrace
+36 -38
View File
@@ -3,36 +3,13 @@ version: '3.8'
services:
# Backend service using pre-built image
backend:
image: serpentrace_docker-backend:latest
image: serpentrace-backend:latest
container_name: serpentrace-backend
restart: unless-stopped
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- PORT=3000
- DB_HOST=postgres
- DB_PORT=5432
- DB_NAME=serpentrace
- DB_USERNAME=postgres
- DB_PASSWORD=${POSTGRES_PASSWORD}
- REDIS_URL=redis://redis:6379
- REDIS_HOST=redis
- REDIS_PORT=6379
- JWT_SECRET=${JWT_SECRET}
- JWT_EXPIRATION=${JWT_EXPIRATION:-24h}
- JWT_REFRESH_EXPIRATION=${JWT_REFRESH_EXPIRATION:-7d}
- MINIO_ENDPOINT=minio
- MINIO_PORT=9000
- MINIO_ACCESS_KEY=${MINIO_ACCESS_KEY}
- MINIO_SECRET_KEY=${MINIO_SECRET_KEY}
- MINIO_USE_SSL=false
- EMAIL_HOST=${EMAIL_HOST}
- EMAIL_PORT=${EMAIL_PORT}
- EMAIL_SECURE=${EMAIL_SECURE}
- EMAIL_USER=${EMAIL_USER}
- EMAIL_PASS=${EMAIL_PASS}
- EMAIL_FROM=${EMAIL_FROM}
env_file:
- .env.server
volumes:
- backend_logs:/app/logs
depends_on:
@@ -44,20 +21,15 @@ services:
condition: service_healthy
networks:
- serpentrace-network
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
tty: true
# Frontend service using pre-built image
frontend:
image: serpentrace_docker-frontend:latest
image: serpentrace-frontend:latest
container_name: serpentrace-frontend
restart: unless-stopped
ports:
- "80:80"
- "8080:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
@@ -81,7 +53,7 @@ services:
environment:
POSTGRES_DB: serpentrace
POSTGRES_USER: postgres
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
POSTGRES_PASSWORD: postgres
POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
volumes:
- postgres_data:/var/lib/postgresql/data
@@ -103,7 +75,7 @@ services:
- "6379:6379"
volumes:
- redis_data:/data
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
command: redis-server --appendonly yes
networks:
- serpentrace-network
healthcheck:
@@ -121,8 +93,8 @@ services:
- "9000:9000"
- "9001:9001"
environment:
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY}
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
MINIO_ROOT_USER: serpentrace
MINIO_ROOT_PASSWORD: serpentrace123!
volumes:
- minio_data:/data
command: server /data --console-address ":9001"
@@ -134,6 +106,32 @@ services:
timeout: 5s
retries: 5
# Adminer Database Viewer
adminer:
image: adminer:latest
container_name: serpentrace-adminer
restart: unless-stopped
ports:
- "8083:8080" # Access via http://<server-ip>:8083
depends_on:
- postgres
networks:
- serpentrace-network
# Redis Commander
redis-commander:
image: rediscommander/redis-commander:latest
container_name: serpentrace-redis-commander
restart: unless-stopped
ports:
- "8082:8081" # Access via http://<server-ip>:8082
environment:
REDIS_HOSTS: local:serpentrace-redis:6379
depends_on:
- redis
networks:
- serpentrace-network
volumes:
postgres_data:
driver: local
+5 -5
View File
@@ -24,9 +24,9 @@ if %errorlevel% neq 0 (
exit /b 1
)
REM Check if serpentRaceDocker.tar exists
if not exist "serpentRaceDocker.tar" (
echo [ERROR] serpentRaceDocker.tar not found!
REM Check if serpentrace-images.tar exists
if not exist "serpentrace-images.tar" (
echo [ERROR] serpentrace-images.tar not found!
echo Please ensure the tar file is in the same directory as this script.
pause
exit /b 1
@@ -40,8 +40,8 @@ if not exist ".env.server" (
exit /b 1
)
echo [INFO] Loading Docker images from serpentRaceDocker.tar...
docker load -i serpentRaceDocker.tar
echo [INFO] Loading Docker images from serpentrace-images.tar...
docker load -i serpentrace-images.tar
if %errorlevel% neq 0 (
echo [ERROR] Failed to load Docker images!
pause
+5 -5
View File
@@ -20,9 +20,9 @@ if ! command -v docker-compose &> /dev/null; then
exit 1
fi
# Check if serpentRaceDocker.tar exists
if [ ! -f "serpentRaceDocker.tar" ]; then
echo "[ERROR] serpentRaceDocker.tar not found!"
# Check if serpentrace-images.tar exists
if [ ! -f "serpentrace-images.tar" ]; then
echo "[ERROR] serpentrace-images.tar not found!"
echo "Please ensure the tar file is in the same directory as this script."
exit 1
fi
@@ -34,8 +34,8 @@ if [ ! -f ".env.server" ]; then
exit 1
fi
echo "[INFO] Loading Docker images from serpentRaceDocker.tar..."
docker load -i serpentRaceDocker.tar
echo "[INFO] Loading Docker images from serpentrace-images.tar..."
docker load -i serpentrace-images.tar
echo "[INFO] Images loaded successfully!"
echo
+38 -5
View File
@@ -22,7 +22,7 @@ server {
# API proxy to backend
location /api/ {
proxy_pass http://backend:3000/;
proxy_pass http://backend:3000;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
@@ -45,10 +45,43 @@ server {
proxy_set_header X-Forwarded-Proto $scheme;
}
# Static assets caching
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
expires 1y;
add_header Cache-Control "public, immutable";
# Adminer Database Viewer proxy
location /adminer/ {
proxy_pass http://adminer:8080/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
# Redis Commander proxy
location /redis/ {
proxy_pass http://redis-commander:8081/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect http://redis-commander:8081/ /redis/;
proxy_cache_bypass $http_upgrade;
}
# MinIO Console proxy
location /minio/ {
proxy_pass http://minio:9001/;
proxy_http_version 1.1;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection 'upgrade';
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_redirect http://minio:9001/ /minio/;
sub_filter '<base href="/"' '<base href="/minio/"';
sub_filter_types text/html;
proxy_cache_bypass $http_upgrade;
}
# Health check endpoint
@@ -7,6 +7,7 @@
"Port": 5432,
"MaintenanceDB": "serpentrace",
"Username": "postgres",
"Password": "postgres",
"SSLMode": "prefer",
"Comment": "SerpentRace Production Database"
}
Binary file not shown.
Binary file not shown.
+153 -209
View File
@@ -1,236 +1,180 @@
-- SerpentRace Database Schema
-- Generated from TypeORM Entity Aggregates
-- This file creates the complete database schema without initial data
-- This script was generated by the ERD tool in pgAdmin 4.
-- Please log an issue at https://github.com/pgadmin-org/pgadmin4/issues/new/choose if you find any bugs, including reproduction steps.
BEGIN;
-- Enable UUID extension
-- ===================================================================
-- STEP 1: Enable Required Extensions
-- ===================================================================
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
-- Create Users table
CREATE TABLE "Users" (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"orgid" UUID NULL,
"username" VARCHAR(100) UNIQUE NOT NULL,
"password" VARCHAR(255) NOT NULL,
"email" VARCHAR(255) UNIQUE NOT NULL,
"fname" VARCHAR(100) NOT NULL,
"lname" VARCHAR(100) NOT NULL,
"token" VARCHAR(255) NULL,
"TokenExpires" TIMESTAMP NULL,
"phone" VARCHAR(20) NULL,
"state" INTEGER NOT NULL DEFAULT 0,
"regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"Orglogindate" TIMESTAMP NULL
-- ===================================================================
-- STEP 2: Create Tables
-- ===================================================================
CREATE TABLE IF NOT EXISTS public."ChatArchives"
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
"chatId" uuid NOT NULL,
"archivedMessages" json NOT NULL,
"archivedAt" timestamp without time zone NOT NULL,
"createDate" timestamp without time zone NOT NULL DEFAULT now(),
"chatType" character varying(50) COLLATE pg_catalog."default" NOT NULL,
"chatName" character varying(255) COLLATE pg_catalog."default",
"gameId" uuid,
participants uuid[] NOT NULL,
CONSTRAINT "PK_fe62979fc2061d7afe278d3f14e" PRIMARY KEY (id)
);
-- Create Organizations table
CREATE TABLE "Organizations" (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"name" VARCHAR(255) NOT NULL,
"contactfname" VARCHAR(100) NOT NULL,
"contactlname" VARCHAR(100) NOT NULL,
"contactphone" VARCHAR(20) NOT NULL,
"contactemail" VARCHAR(255) NOT NULL,
"state" INTEGER NOT NULL DEFAULT 0,
"regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updatedate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"url" VARCHAR(500) NULL,
"userinorg" INTEGER NOT NULL DEFAULT 0,
"maxOrganizationalDecks" INTEGER NULL
CREATE TABLE IF NOT EXISTS public."Chats"
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
type character varying(50) COLLATE pg_catalog."default" NOT NULL DEFAULT 'direct'::character varying,
name character varying(255) COLLATE pg_catalog."default",
"gameId" uuid,
"createdBy" uuid,
users uuid[] NOT NULL,
messages json NOT NULL DEFAULT '[]'::json,
"lastActivity" timestamp without time zone,
"createDate" timestamp without time zone NOT NULL DEFAULT now(),
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
state integer NOT NULL DEFAULT 0,
"archiveDate" timestamp without time zone,
CONSTRAINT "PK_64c36c2b8d86a0d5de4cf64de8d" PRIMARY KEY (id)
);
-- Create Decks table
CREATE TABLE "Decks" (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"name" VARCHAR(255) NOT NULL,
"type" INTEGER NOT NULL,
"user_id" UUID NOT NULL,
"creation_date" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"cards" JSONB NOT NULL DEFAULT '[]',
"played_number" INTEGER NOT NULL DEFAULT 0,
"ctype" INTEGER NOT NULL DEFAULT 0,
"update_date" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"state" INTEGER NOT NULL DEFAULT 0,
"organization_id" UUID NULL
CREATE TABLE IF NOT EXISTS public."Contacts"
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
name character varying(255) COLLATE pg_catalog."default" NOT NULL,
email character varying(255) COLLATE pg_catalog."default" NOT NULL,
userid uuid,
type integer NOT NULL,
txt text COLLATE pg_catalog."default" NOT NULL,
state integer NOT NULL DEFAULT 0,
"createDate" timestamp without time zone NOT NULL DEFAULT now(),
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
"adminResponse" text COLLATE pg_catalog."default",
"responseDate" timestamp without time zone,
"respondedBy" uuid,
CONSTRAINT "PK_68782cec65c8eef577c62958273" PRIMARY KEY (id)
);
-- Create Chats table
CREATE TABLE "Chats" (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"type" VARCHAR(50) NOT NULL DEFAULT 'direct',
"name" VARCHAR(255) NULL,
"gameId" UUID NULL,
"createdBy" UUID NULL,
"users" UUID[] NOT NULL,
"messages" JSONB NOT NULL DEFAULT '[]',
"lastActivity" TIMESTAMP NULL,
"createDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"state" INTEGER NOT NULL DEFAULT 0,
"archiveDate" TIMESTAMP NULL
CREATE TABLE IF NOT EXISTS public."Decks"
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
name character varying(255) COLLATE pg_catalog."default" NOT NULL,
type integer NOT NULL,
user_id uuid NOT NULL,
creation_date timestamp without time zone NOT NULL DEFAULT now(),
cards json NOT NULL,
played_number integer NOT NULL DEFAULT 0,
ctype integer NOT NULL DEFAULT 0,
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
state integer NOT NULL DEFAULT 0,
organization_id uuid,
CONSTRAINT "PK_001f26cb3ec39c1f25269943473" PRIMARY KEY (id)
);
-- Create Contacts table
CREATE TABLE "Contacts" (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"name" VARCHAR(255) NOT NULL,
"email" VARCHAR(255) NOT NULL,
"userid" UUID NULL,
"type" INTEGER NOT NULL,
"txt" TEXT NOT NULL,
"state" INTEGER NOT NULL DEFAULT 0,
"createDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"adminResponse" TEXT NULL,
"responseDate" TIMESTAMP NULL,
"respondedBy" UUID NULL
CREATE TABLE IF NOT EXISTS public."Games"
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
gamecode character varying(10) COLLATE pg_catalog."default" NOT NULL,
maxplayers integer NOT NULL,
logintype integer NOT NULL DEFAULT 0,
boardsize integer NOT NULL DEFAULT 50,
"createdBy" uuid NOT NULL,
organizationid uuid,
decks jsonb NOT NULL DEFAULT '[]'::jsonb,
playerids uuid[] NOT NULL DEFAULT '{}'::uuid[],
"winnerId" uuid,
state integer NOT NULL DEFAULT 0,
"createDate" timestamp without time zone NOT NULL DEFAULT now(),
start_date timestamp without time zone,
"finishDate" timestamp without time zone,
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
"organizationId" uuid,
CONSTRAINT "PK_1950492f583d31609c5e9fbbe12" PRIMARY KEY (id),
CONSTRAINT "UQ_9d52c646079cbe6f242a85c5c41" UNIQUE (gamecode)
);
-- Create Games table
CREATE TABLE "Games" (
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
"gamecode" VARCHAR(10) UNIQUE NOT NULL,
"maxplayers" INTEGER NOT NULL,
"logintype" INTEGER NOT NULL DEFAULT 0,
"state" INTEGER NOT NULL DEFAULT 0,
"playerids" UUID[] NOT NULL DEFAULT '{}',
"decks" JSONB NOT NULL DEFAULT '[]',
"boardsize" INTEGER NOT NULL DEFAULT 50,
"createDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
"finishDate" TIMESTAMP NULL,
"winnerid" UUID NULL,
"createdBy" UUID NOT NULL,
"organizationid" UUID NULL
CREATE TABLE IF NOT EXISTS public."Organizations"
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
name character varying(255) COLLATE pg_catalog."default" NOT NULL,
contactfname character varying(100) COLLATE pg_catalog."default" NOT NULL,
contactlname character varying(100) COLLATE pg_catalog."default" NOT NULL,
contactphone character varying(20) COLLATE pg_catalog."default" NOT NULL,
contactemail character varying(255) COLLATE pg_catalog."default" NOT NULL,
state integer NOT NULL DEFAULT 0,
regdate timestamp without time zone NOT NULL DEFAULT now(),
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
url character varying(500) COLLATE pg_catalog."default",
userinorg integer NOT NULL DEFAULT 0,
"maxOrganizationalDecks" integer,
CONSTRAINT "PK_e0690a31419f6666194423526f2" PRIMARY KEY (id)
);
-- Add Foreign Key Constraints
ALTER TABLE "Users"
ADD CONSTRAINT "FK_Users_Organizations"
FOREIGN KEY ("orgid") REFERENCES "Organizations"("id") ON DELETE SET NULL;
CREATE TABLE IF NOT EXISTS public."Users"
(
id uuid NOT NULL DEFAULT uuid_generate_v4(),
orgid uuid,
username character varying(100) COLLATE pg_catalog."default" NOT NULL,
password character varying(255) COLLATE pg_catalog."default" NOT NULL,
email character varying(255) COLLATE pg_catalog."default" NOT NULL,
fname character varying(100) COLLATE pg_catalog."default" NOT NULL,
lname character varying(100) COLLATE pg_catalog."default" NOT NULL,
token character varying(255) COLLATE pg_catalog."default",
"TokenExpires" timestamp without time zone,
phone character varying(20) COLLATE pg_catalog."default",
state integer NOT NULL DEFAULT 0,
regdate timestamp without time zone NOT NULL DEFAULT now(),
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
"Orglogindate" timestamp without time zone,
CONSTRAINT "PK_16d4f7d636df336db11d87413e3" PRIMARY KEY (id),
CONSTRAINT "UQ_3c3ab3f49a87e6ddb607f3c4945" UNIQUE (email),
CONSTRAINT "UQ_ffc81a3b97dcbf8e320d5106c0d" UNIQUE (username)
);
ALTER TABLE "Decks"
ADD CONSTRAINT "FK_Decks_Users"
FOREIGN KEY ("user_id") REFERENCES "Users"("id") ON DELETE CASCADE;
CREATE TABLE IF NOT EXISTS public.migrations
(
id serial NOT NULL,
"timestamp" bigint NOT NULL,
name character varying COLLATE pg_catalog."default" NOT NULL,
CONSTRAINT "PK_8c82d7f526340ab734260ea46be" PRIMARY KEY (id)
);
ALTER TABLE "Decks"
ADD CONSTRAINT "FK_Decks_Organizations"
FOREIGN KEY ("organization_id") REFERENCES "Organizations"("id") ON DELETE SET NULL;
ALTER TABLE IF EXISTS public."Decks"
ADD CONSTRAINT "FK_06ee28f90d68543a03b14aebe13" FOREIGN KEY (organization_id)
REFERENCES public."Organizations" (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
ALTER TABLE "Contacts"
ADD CONSTRAINT "FK_Contacts_Users"
FOREIGN KEY ("userid") REFERENCES "Users"("id") ON DELETE SET NULL;
ALTER TABLE "Contacts"
ADD CONSTRAINT "FK_Contacts_RespondedBy"
FOREIGN KEY ("respondedBy") REFERENCES "Users"("id") ON DELETE SET NULL;
ALTER TABLE IF EXISTS public."Decks"
ADD CONSTRAINT "FK_a39059433e29882e1309d3a5e70" FOREIGN KEY (user_id)
REFERENCES public."Users" (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
ALTER TABLE "Chats"
ADD CONSTRAINT "FK_Chats_CreatedBy"
FOREIGN KEY ("createdBy") REFERENCES "Users"("id") ON DELETE SET NULL;
ALTER TABLE "Chats"
ADD CONSTRAINT "FK_Chats_Games"
FOREIGN KEY ("gameId") REFERENCES "Games"("id") ON DELETE SET NULL;
ALTER TABLE IF EXISTS public."Games"
ADD CONSTRAINT "FK_330362bff8b25bb573f31fb4023" FOREIGN KEY ("winnerId")
REFERENCES public."Users" (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
ALTER TABLE "Games"
ADD CONSTRAINT "FK_Games_CreatedBy"
FOREIGN KEY ("createdBy") REFERENCES "Users"("id") ON DELETE CASCADE;
ALTER TABLE "Games"
ADD CONSTRAINT "FK_Games_Organizations"
FOREIGN KEY ("organizationid") REFERENCES "Organizations"("id") ON DELETE SET NULL;
ALTER TABLE IF EXISTS public."Games"
ADD CONSTRAINT "FK_e3c4e8898fa026a5551aefc4f62" FOREIGN KEY ("organizationId")
REFERENCES public."Organizations" (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
ALTER TABLE "Games"
ADD CONSTRAINT "FK_Games_Winner"
FOREIGN KEY ("winnerid") REFERENCES "Users"("id") ON DELETE SET NULL;
-- Create Indexes for Performance
CREATE INDEX "IDX_Users_Username" ON "Users" ("username");
CREATE INDEX "IDX_Users_Email" ON "Users" ("email");
CREATE INDEX "IDX_Users_OrgId" ON "Users" ("orgid");
CREATE INDEX "IDX_Users_State" ON "Users" ("state");
ALTER TABLE IF EXISTS public."Games"
ADD CONSTRAINT "FK_f32db60863a8a393b30aa222cd5" FOREIGN KEY ("createdBy")
REFERENCES public."Users" (id) MATCH SIMPLE
ON UPDATE NO ACTION
ON DELETE NO ACTION;
CREATE INDEX "IDX_Organizations_Name" ON "Organizations" ("name");
CREATE INDEX "IDX_Organizations_State" ON "Organizations" ("state");
CREATE INDEX "IDX_Decks_UserId" ON "Decks" ("user_id");
CREATE INDEX "IDX_Decks_Type" ON "Decks" ("type");
CREATE INDEX "IDX_Decks_CType" ON "Decks" ("ctype");
CREATE INDEX "IDX_Decks_State" ON "Decks" ("state");
CREATE INDEX "IDX_Decks_OrganizationId" ON "Decks" ("organization_id");
CREATE INDEX "IDX_Chats_Type" ON "Chats" ("type");
CREATE INDEX "IDX_Chats_State" ON "Chats" ("state");
CREATE INDEX "IDX_Chats_GameId" ON "Chats" ("gameId");
CREATE INDEX "IDX_Chats_CreatedBy" ON "Chats" ("createdBy");
CREATE INDEX "IDX_Contacts_Type" ON "Contacts" ("type");
CREATE INDEX "IDX_Contacts_State" ON "Contacts" ("state");
CREATE INDEX "IDX_Contacts_UserId" ON "Contacts" ("userid");
CREATE INDEX "IDX_Games_GameCode" ON "Games" ("gamecode");
CREATE INDEX "IDX_Games_State" ON "Games" ("state");
CREATE INDEX "IDX_Games_CreatedBy" ON "Games" ("createdBy");
CREATE INDEX "IDX_Games_OrganizationId" ON "Games" ("organizationid");
-- Create update trigger for updatedate columns
CREATE OR REPLACE FUNCTION update_updatedate_column()
RETURNS TRIGGER AS $$
BEGIN
NEW.updatedate = CURRENT_TIMESTAMP;
RETURN NEW;
END;
$$ language 'plpgsql';
-- Apply update triggers
CREATE TRIGGER update_users_updatedate
BEFORE UPDATE ON "Users"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_organizations_updatedate
BEFORE UPDATE ON "Organizations"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_decks_updatedate
BEFORE UPDATE ON "Decks"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_chats_updatedate
BEFORE UPDATE ON "Chats"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_contacts_updatedate
BEFORE UPDATE ON "Contacts"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
CREATE TRIGGER update_games_updatedate
BEFORE UPDATE ON "Games"
FOR EACH ROW EXECUTE FUNCTION update_updatedate_column();
-- Comments for documentation
COMMENT ON TABLE "Users" IS 'User accounts with authentication and profile information';
COMMENT ON TABLE "Organizations" IS 'Organizations that can have multiple users and premium features';
COMMENT ON TABLE "Decks" IS 'Card decks for the game, can be public, private, or organizational';
COMMENT ON TABLE "Chats" IS 'Chat system supporting direct messages, groups, and game chats';
COMMENT ON TABLE "Contacts" IS 'Contact form submissions and support tickets';
COMMENT ON TABLE "Games" IS 'Game sessions with players, decks, and game state';
-- Enum value comments
COMMENT ON COLUMN "Users"."state" IS '0=REGISTERED_NOT_VERIFIED, 1=VERIFIED_REGULAR, 2=VERIFIED_PREMIUM, 3=SOFT_DELETE, 4=DEACTIVATED, 5=ADMIN';
COMMENT ON COLUMN "Organizations"."state" IS '0=REGISTERED, 1=ACTIVE, 2=SOFT_DELETE';
COMMENT ON COLUMN "Decks"."type" IS '0=LUCK, 1=JOKER, 2=QUESTION';
COMMENT ON COLUMN "Decks"."ctype" IS '0=PUBLIC, 1=PRIVATE, 2=ORGANIZATION';
COMMENT ON COLUMN "Decks"."state" IS '0=ACTIVE, 1=SOFT_DELETE';
COMMENT ON COLUMN "Chats"."type" IS 'direct, group, game';
COMMENT ON COLUMN "Chats"."state" IS '0=ACTIVE, 1=ARCHIVE, 2=SOFT_DELETE';
COMMENT ON COLUMN "Contacts"."type" IS '0=BUG, 1=PROBLEM, 2=QUESTION, 3=SALES, 4=OTHER';
COMMENT ON COLUMN "Contacts"."state" IS '0=ACTIVE, 1=RESOLVED, 2=SOFT_DELETE';
COMMENT ON COLUMN "Games"."state" IS '0=WAITING, 1=ACTIVE, 2=FINISHED, 3=CANCELLED';
COMMENT ON COLUMN "Games"."logintype" IS '0=PUBLIC, 1=PRIVATE, 2=ORGANIZATION';
-- Grant permissions for application user
-- Note: Replace 'serpentrace_app' with your actual application database user
-- GRANT ALL PRIVILEGES ON ALL TABLES IN SCHEMA public TO serpentrace_app;
-- GRANT ALL PRIVILEGES ON ALL SEQUENCES IN SCHEMA public TO serpentrace_app;
-- GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA public TO serpentrace_app;