Compare commits
12 Commits
18e213bc31
...
deployment
| Author | SHA1 | Date | |
|---|---|---|---|
| e634b89b70 | |||
| b39ca0930a | |||
| 822254f95e | |||
| c316db9b32 | |||
| d53fe4bb3e | |||
| 1c1792e7e1 | |||
| 0566b58240 | |||
| 88c153eb6a | |||
| 8c27b5ea2f | |||
| a95ee33123 | |||
| 9653537bc9 | |||
| 4a5486caa4 |
@@ -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.
@@ -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*
|
|
||||||
@@ -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
|
|
||||||
@@ -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
@@ -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
|
|
||||||
@@ -28,12 +28,12 @@ JWT_REFRESH_EXPIRATION=7d
|
|||||||
|
|
||||||
# Email Configuration (SMTP)
|
# Email Configuration (SMTP)
|
||||||
# CHANGE THESE: Configure your email provider
|
# CHANGE THESE: Configure your email provider
|
||||||
EMAIL_HOST=smtp.yourmailprovider.com
|
EMAIL_HOST=mail.serpentrace.hu
|
||||||
EMAIL_PORT=587
|
EMAIL_PORT=465
|
||||||
EMAIL_SECURE=false
|
EMAIL_SECURE=true
|
||||||
EMAIL_USER=your_email@yourdomain.com
|
EMAIL_USER=noreply@serpentrace.hu
|
||||||
EMAIL_PASS=your_email_password
|
EMAIL_PASS=ZUx720ece&Cin&F{
|
||||||
EMAIL_FROM="SerpentRace <noreply@yourdomain.com>"
|
EMAIL_FROM="SerpentRace <noreply@serpentrace.hu>"
|
||||||
|
|
||||||
# MinIO Object Storage
|
# MinIO Object Storage
|
||||||
MINIO_ENDPOINT=minio
|
MINIO_ENDPOINT=minio
|
||||||
@@ -45,7 +45,8 @@ MINIO_SECRET_KEY=CHANGE_THIS_MINIO_SECRET_KEY_123!
|
|||||||
MINIO_BUCKET_NAME=serpentrace-logs
|
MINIO_BUCKET_NAME=serpentrace-logs
|
||||||
|
|
||||||
# Application Settings
|
# 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
|
PORT=3000
|
||||||
|
|
||||||
# Chat System Limits
|
# Chat System Limits
|
||||||
|
|||||||
@@ -201,3 +201,11 @@ docker-compose -f docker-compose.deploy.yml up -d
|
|||||||
- Redis: 7-alpine
|
- Redis: 7-alpine
|
||||||
- MinIO: Latest
|
- MinIO: Latest
|
||||||
- Nginx: Alpine
|
- Nginx: Alpine
|
||||||
|
|
||||||
|
|
||||||
|
## DataBase information
|
||||||
|
- System: PostgreSQL
|
||||||
|
- Server: postgres
|
||||||
|
- Username: postgres
|
||||||
|
- Password: postgres
|
||||||
|
- Database: serpentrace
|
||||||
@@ -3,36 +3,13 @@ version: '3.8'
|
|||||||
services:
|
services:
|
||||||
# Backend service using pre-built image
|
# Backend service using pre-built image
|
||||||
backend:
|
backend:
|
||||||
image: serpentrace_docker-backend:latest
|
image: serpentrace-backend:latest
|
||||||
container_name: serpentrace-backend
|
container_name: serpentrace-backend
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "3000:3000"
|
- "3000:3000"
|
||||||
environment:
|
env_file:
|
||||||
- NODE_ENV=production
|
- .env.server
|
||||||
- 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}
|
|
||||||
volumes:
|
volumes:
|
||||||
- backend_logs:/app/logs
|
- backend_logs:/app/logs
|
||||||
depends_on:
|
depends_on:
|
||||||
@@ -44,20 +21,15 @@ services:
|
|||||||
condition: service_healthy
|
condition: service_healthy
|
||||||
networks:
|
networks:
|
||||||
- serpentrace-network
|
- serpentrace-network
|
||||||
healthcheck:
|
tty: true
|
||||||
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
|
|
||||||
interval: 30s
|
|
||||||
timeout: 10s
|
|
||||||
retries: 3
|
|
||||||
start_period: 40s
|
|
||||||
|
|
||||||
# Frontend service using pre-built image
|
# Frontend service using pre-built image
|
||||||
frontend:
|
frontend:
|
||||||
image: serpentrace_docker-frontend:latest
|
image: serpentrace-frontend:latest
|
||||||
container_name: serpentrace-frontend
|
container_name: serpentrace-frontend
|
||||||
restart: unless-stopped
|
restart: unless-stopped
|
||||||
ports:
|
ports:
|
||||||
- "80:80"
|
- "8080:80"
|
||||||
- "443:443"
|
- "443:443"
|
||||||
volumes:
|
volumes:
|
||||||
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
|
||||||
@@ -81,7 +53,7 @@ services:
|
|||||||
environment:
|
environment:
|
||||||
POSTGRES_DB: serpentrace
|
POSTGRES_DB: serpentrace
|
||||||
POSTGRES_USER: postgres
|
POSTGRES_USER: postgres
|
||||||
POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
|
POSTGRES_PASSWORD: postgres
|
||||||
POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
|
POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
|
||||||
volumes:
|
volumes:
|
||||||
- postgres_data:/var/lib/postgresql/data
|
- postgres_data:/var/lib/postgresql/data
|
||||||
@@ -103,7 +75,7 @@ services:
|
|||||||
- "6379:6379"
|
- "6379:6379"
|
||||||
volumes:
|
volumes:
|
||||||
- redis_data:/data
|
- redis_data:/data
|
||||||
command: redis-server --appendonly yes --requirepass ${REDIS_PASSWORD}
|
command: redis-server --appendonly yes
|
||||||
networks:
|
networks:
|
||||||
- serpentrace-network
|
- serpentrace-network
|
||||||
healthcheck:
|
healthcheck:
|
||||||
@@ -121,8 +93,8 @@ services:
|
|||||||
- "9000:9000"
|
- "9000:9000"
|
||||||
- "9001:9001"
|
- "9001:9001"
|
||||||
environment:
|
environment:
|
||||||
MINIO_ROOT_USER: ${MINIO_ACCESS_KEY}
|
MINIO_ROOT_USER: serpentrace
|
||||||
MINIO_ROOT_PASSWORD: ${MINIO_SECRET_KEY}
|
MINIO_ROOT_PASSWORD: serpentrace123!
|
||||||
volumes:
|
volumes:
|
||||||
- minio_data:/data
|
- minio_data:/data
|
||||||
command: server /data --console-address ":9001"
|
command: server /data --console-address ":9001"
|
||||||
@@ -134,6 +106,32 @@ services:
|
|||||||
timeout: 5s
|
timeout: 5s
|
||||||
retries: 5
|
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:
|
volumes:
|
||||||
postgres_data:
|
postgres_data:
|
||||||
driver: local
|
driver: local
|
||||||
|
|||||||
@@ -24,9 +24,9 @@ if %errorlevel% neq 0 (
|
|||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
REM Check if serpentRaceDocker.tar exists
|
REM Check if serpentrace-images.tar exists
|
||||||
if not exist "serpentRaceDocker.tar" (
|
if not exist "serpentrace-images.tar" (
|
||||||
echo [ERROR] serpentRaceDocker.tar not found!
|
echo [ERROR] serpentrace-images.tar not found!
|
||||||
echo Please ensure the tar file is in the same directory as this script.
|
echo Please ensure the tar file is in the same directory as this script.
|
||||||
pause
|
pause
|
||||||
exit /b 1
|
exit /b 1
|
||||||
@@ -40,8 +40,8 @@ if not exist ".env.server" (
|
|||||||
exit /b 1
|
exit /b 1
|
||||||
)
|
)
|
||||||
|
|
||||||
echo [INFO] Loading Docker images from serpentRaceDocker.tar...
|
echo [INFO] Loading Docker images from serpentrace-images.tar...
|
||||||
docker load -i serpentRaceDocker.tar
|
docker load -i serpentrace-images.tar
|
||||||
if %errorlevel% neq 0 (
|
if %errorlevel% neq 0 (
|
||||||
echo [ERROR] Failed to load Docker images!
|
echo [ERROR] Failed to load Docker images!
|
||||||
pause
|
pause
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ if ! command -v docker-compose &> /dev/null; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# Check if serpentRaceDocker.tar exists
|
# Check if serpentrace-images.tar exists
|
||||||
if [ ! -f "serpentRaceDocker.tar" ]; then
|
if [ ! -f "serpentrace-images.tar" ]; then
|
||||||
echo "[ERROR] serpentRaceDocker.tar not found!"
|
echo "[ERROR] serpentrace-images.tar not found!"
|
||||||
echo "Please ensure the tar file is in the same directory as this script."
|
echo "Please ensure the tar file is in the same directory as this script."
|
||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
@@ -34,8 +34,8 @@ if [ ! -f ".env.server" ]; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
echo "[INFO] Loading Docker images from serpentRaceDocker.tar..."
|
echo "[INFO] Loading Docker images from serpentrace-images.tar..."
|
||||||
docker load -i serpentRaceDocker.tar
|
docker load -i serpentrace-images.tar
|
||||||
|
|
||||||
echo "[INFO] Images loaded successfully!"
|
echo "[INFO] Images loaded successfully!"
|
||||||
echo
|
echo
|
||||||
|
|||||||
+38
-5
@@ -22,7 +22,7 @@ server {
|
|||||||
|
|
||||||
# API proxy to backend
|
# API proxy to backend
|
||||||
location /api/ {
|
location /api/ {
|
||||||
proxy_pass http://backend:3000/;
|
proxy_pass http://backend:3000;
|
||||||
proxy_http_version 1.1;
|
proxy_http_version 1.1;
|
||||||
proxy_set_header Upgrade $http_upgrade;
|
proxy_set_header Upgrade $http_upgrade;
|
||||||
proxy_set_header Connection 'upgrade';
|
proxy_set_header Connection 'upgrade';
|
||||||
@@ -45,10 +45,43 @@ server {
|
|||||||
proxy_set_header X-Forwarded-Proto $scheme;
|
proxy_set_header X-Forwarded-Proto $scheme;
|
||||||
}
|
}
|
||||||
|
|
||||||
# Static assets caching
|
# Adminer Database Viewer proxy
|
||||||
location ~* \.(js|css|png|jpg|jpeg|gif|ico|svg)$ {
|
location /adminer/ {
|
||||||
expires 1y;
|
proxy_pass http://adminer:8080/;
|
||||||
add_header Cache-Control "public, immutable";
|
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
|
# Health check endpoint
|
||||||
|
|||||||
@@ -7,6 +7,7 @@
|
|||||||
"Port": 5432,
|
"Port": 5432,
|
||||||
"MaintenanceDB": "serpentrace",
|
"MaintenanceDB": "serpentrace",
|
||||||
"Username": "postgres",
|
"Username": "postgres",
|
||||||
|
"Password": "postgres",
|
||||||
"SSLMode": "prefer",
|
"SSLMode": "prefer",
|
||||||
"Comment": "SerpentRace Production Database"
|
"Comment": "SerpentRace Production Database"
|
||||||
}
|
}
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
+153
-209
@@ -1,236 +1,180 @@
|
|||||||
-- SerpentRace Database Schema
|
-- This script was generated by the ERD tool in pgAdmin 4.
|
||||||
-- Generated from TypeORM Entity Aggregates
|
-- Please log an issue at https://github.com/pgadmin-org/pgadmin4/issues/new/choose if you find any bugs, including reproduction steps.
|
||||||
-- This file creates the complete database schema without initial data
|
BEGIN;
|
||||||
|
|
||||||
-- Enable UUID extension
|
-- ===================================================================
|
||||||
|
-- STEP 1: Enable Required Extensions
|
||||||
|
-- ===================================================================
|
||||||
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
CREATE EXTENSION IF NOT EXISTS "uuid-ossp";
|
||||||
|
|
||||||
-- Create Users table
|
-- ===================================================================
|
||||||
CREATE TABLE "Users" (
|
-- STEP 2: Create Tables
|
||||||
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
-- ===================================================================
|
||||||
"orgid" UUID NULL,
|
|
||||||
"username" VARCHAR(100) UNIQUE NOT NULL,
|
CREATE TABLE IF NOT EXISTS public."ChatArchives"
|
||||||
"password" VARCHAR(255) NOT NULL,
|
(
|
||||||
"email" VARCHAR(255) UNIQUE NOT NULL,
|
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
"fname" VARCHAR(100) NOT NULL,
|
"chatId" uuid NOT NULL,
|
||||||
"lname" VARCHAR(100) NOT NULL,
|
"archivedMessages" json NOT NULL,
|
||||||
"token" VARCHAR(255) NULL,
|
"archivedAt" timestamp without time zone NOT NULL,
|
||||||
"TokenExpires" TIMESTAMP NULL,
|
"createDate" timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"phone" VARCHAR(20) NULL,
|
"chatType" character varying(50) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"state" INTEGER NOT NULL DEFAULT 0,
|
"chatName" character varying(255) COLLATE pg_catalog."default",
|
||||||
"regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"gameId" uuid,
|
||||||
"updatedate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
participants uuid[] NOT NULL,
|
||||||
"Orglogindate" TIMESTAMP NULL
|
CONSTRAINT "PK_fe62979fc2061d7afe278d3f14e" PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Create Organizations table
|
CREATE TABLE IF NOT EXISTS public."Chats"
|
||||||
CREATE TABLE "Organizations" (
|
(
|
||||||
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
"name" VARCHAR(255) NOT NULL,
|
type character varying(50) COLLATE pg_catalog."default" NOT NULL DEFAULT 'direct'::character varying,
|
||||||
"contactfname" VARCHAR(100) NOT NULL,
|
name character varying(255) COLLATE pg_catalog."default",
|
||||||
"contactlname" VARCHAR(100) NOT NULL,
|
"gameId" uuid,
|
||||||
"contactphone" VARCHAR(20) NOT NULL,
|
"createdBy" uuid,
|
||||||
"contactemail" VARCHAR(255) NOT NULL,
|
users uuid[] NOT NULL,
|
||||||
"state" INTEGER NOT NULL DEFAULT 0,
|
messages json NOT NULL DEFAULT '[]'::json,
|
||||||
"regdate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"lastActivity" timestamp without time zone,
|
||||||
"updatedate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createDate" timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"url" VARCHAR(500) NULL,
|
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"userinorg" INTEGER NOT NULL DEFAULT 0,
|
state integer NOT NULL DEFAULT 0,
|
||||||
"maxOrganizationalDecks" INTEGER NULL
|
"archiveDate" timestamp without time zone,
|
||||||
|
CONSTRAINT "PK_64c36c2b8d86a0d5de4cf64de8d" PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Create Decks table
|
CREATE TABLE IF NOT EXISTS public."Contacts"
|
||||||
CREATE TABLE "Decks" (
|
(
|
||||||
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
"name" VARCHAR(255) NOT NULL,
|
name character varying(255) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"type" INTEGER NOT NULL,
|
email character varying(255) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"user_id" UUID NOT NULL,
|
userid uuid,
|
||||||
"creation_date" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
type integer NOT NULL,
|
||||||
"cards" JSONB NOT NULL DEFAULT '[]',
|
txt text COLLATE pg_catalog."default" NOT NULL,
|
||||||
"played_number" INTEGER NOT NULL DEFAULT 0,
|
state integer NOT NULL DEFAULT 0,
|
||||||
"ctype" INTEGER NOT NULL DEFAULT 0,
|
"createDate" timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"update_date" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"state" INTEGER NOT NULL DEFAULT 0,
|
"adminResponse" text COLLATE pg_catalog."default",
|
||||||
"organization_id" UUID NULL
|
"responseDate" timestamp without time zone,
|
||||||
|
"respondedBy" uuid,
|
||||||
|
CONSTRAINT "PK_68782cec65c8eef577c62958273" PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Create Chats table
|
CREATE TABLE IF NOT EXISTS public."Decks"
|
||||||
CREATE TABLE "Chats" (
|
(
|
||||||
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
"type" VARCHAR(50) NOT NULL DEFAULT 'direct',
|
name character varying(255) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"name" VARCHAR(255) NULL,
|
type integer NOT NULL,
|
||||||
"gameId" UUID NULL,
|
user_id uuid NOT NULL,
|
||||||
"createdBy" UUID NULL,
|
creation_date timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"users" UUID[] NOT NULL,
|
cards json NOT NULL,
|
||||||
"messages" JSONB NOT NULL DEFAULT '[]',
|
played_number integer NOT NULL DEFAULT 0,
|
||||||
"lastActivity" TIMESTAMP NULL,
|
ctype integer NOT NULL DEFAULT 0,
|
||||||
"createDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
state integer NOT NULL DEFAULT 0,
|
||||||
"state" INTEGER NOT NULL DEFAULT 0,
|
organization_id uuid,
|
||||||
"archiveDate" TIMESTAMP NULL
|
CONSTRAINT "PK_001f26cb3ec39c1f25269943473" PRIMARY KEY (id)
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Create Contacts table
|
CREATE TABLE IF NOT EXISTS public."Games"
|
||||||
CREATE TABLE "Contacts" (
|
(
|
||||||
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
"name" VARCHAR(255) NOT NULL,
|
gamecode character varying(10) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"email" VARCHAR(255) NOT NULL,
|
maxplayers integer NOT NULL,
|
||||||
"userid" UUID NULL,
|
logintype integer NOT NULL DEFAULT 0,
|
||||||
"type" INTEGER NOT NULL,
|
boardsize integer NOT NULL DEFAULT 50,
|
||||||
"txt" TEXT NOT NULL,
|
"createdBy" uuid NOT NULL,
|
||||||
"state" INTEGER NOT NULL DEFAULT 0,
|
organizationid uuid,
|
||||||
"createDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
decks jsonb NOT NULL DEFAULT '[]'::jsonb,
|
||||||
"updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
playerids uuid[] NOT NULL DEFAULT '{}'::uuid[],
|
||||||
"adminResponse" TEXT NULL,
|
"winnerId" uuid,
|
||||||
"responseDate" TIMESTAMP NULL,
|
state integer NOT NULL DEFAULT 0,
|
||||||
"respondedBy" UUID NULL
|
"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 IF NOT EXISTS public."Organizations"
|
||||||
CREATE TABLE "Games" (
|
(
|
||||||
"id" UUID PRIMARY KEY DEFAULT uuid_generate_v4(),
|
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
"gamecode" VARCHAR(10) UNIQUE NOT NULL,
|
name character varying(255) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"maxplayers" INTEGER NOT NULL,
|
contactfname character varying(100) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"logintype" INTEGER NOT NULL DEFAULT 0,
|
contactlname character varying(100) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"state" INTEGER NOT NULL DEFAULT 0,
|
contactphone character varying(20) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"playerids" UUID[] NOT NULL DEFAULT '{}',
|
contactemail character varying(255) COLLATE pg_catalog."default" NOT NULL,
|
||||||
"decks" JSONB NOT NULL DEFAULT '[]',
|
state integer NOT NULL DEFAULT 0,
|
||||||
"boardsize" INTEGER NOT NULL DEFAULT 50,
|
regdate timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"createDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"updateDate" timestamp without time zone NOT NULL DEFAULT now(),
|
||||||
"updateDate" TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
url character varying(500) COLLATE pg_catalog."default",
|
||||||
"finishDate" TIMESTAMP NULL,
|
userinorg integer NOT NULL DEFAULT 0,
|
||||||
"winnerid" UUID NULL,
|
"maxOrganizationalDecks" integer,
|
||||||
"createdBy" UUID NOT NULL,
|
CONSTRAINT "PK_e0690a31419f6666194423526f2" PRIMARY KEY (id)
|
||||||
"organizationid" UUID NULL
|
|
||||||
);
|
);
|
||||||
|
|
||||||
-- Add Foreign Key Constraints
|
CREATE TABLE IF NOT EXISTS public."Users"
|
||||||
ALTER TABLE "Users"
|
(
|
||||||
ADD CONSTRAINT "FK_Users_Organizations"
|
id uuid NOT NULL DEFAULT uuid_generate_v4(),
|
||||||
FOREIGN KEY ("orgid") REFERENCES "Organizations"("id") ON DELETE SET NULL;
|
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"
|
CREATE TABLE IF NOT EXISTS public.migrations
|
||||||
ADD CONSTRAINT "FK_Decks_Users"
|
(
|
||||||
FOREIGN KEY ("user_id") REFERENCES "Users"("id") ON DELETE CASCADE;
|
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"
|
ALTER TABLE IF EXISTS public."Decks"
|
||||||
ADD CONSTRAINT "FK_Decks_Organizations"
|
ADD CONSTRAINT "FK_06ee28f90d68543a03b14aebe13" FOREIGN KEY (organization_id)
|
||||||
FOREIGN KEY ("organization_id") REFERENCES "Organizations"("id") ON DELETE SET NULL;
|
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"
|
ALTER TABLE IF EXISTS public."Decks"
|
||||||
ADD CONSTRAINT "FK_Contacts_RespondedBy"
|
ADD CONSTRAINT "FK_a39059433e29882e1309d3a5e70" FOREIGN KEY (user_id)
|
||||||
FOREIGN KEY ("respondedBy") REFERENCES "Users"("id") ON DELETE SET NULL;
|
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"
|
ALTER TABLE IF EXISTS public."Games"
|
||||||
ADD CONSTRAINT "FK_Chats_Games"
|
ADD CONSTRAINT "FK_330362bff8b25bb573f31fb4023" FOREIGN KEY ("winnerId")
|
||||||
FOREIGN KEY ("gameId") REFERENCES "Games"("id") ON DELETE SET NULL;
|
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"
|
ALTER TABLE IF EXISTS public."Games"
|
||||||
ADD CONSTRAINT "FK_Games_Organizations"
|
ADD CONSTRAINT "FK_e3c4e8898fa026a5551aefc4f62" FOREIGN KEY ("organizationId")
|
||||||
FOREIGN KEY ("organizationid") REFERENCES "Organizations"("id") ON DELETE SET NULL;
|
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
|
ALTER TABLE IF EXISTS public."Games"
|
||||||
CREATE INDEX "IDX_Users_Username" ON "Users" ("username");
|
ADD CONSTRAINT "FK_f32db60863a8a393b30aa222cd5" FOREIGN KEY ("createdBy")
|
||||||
CREATE INDEX "IDX_Users_Email" ON "Users" ("email");
|
REFERENCES public."Users" (id) MATCH SIMPLE
|
||||||
CREATE INDEX "IDX_Users_OrgId" ON "Users" ("orgid");
|
ON UPDATE NO ACTION
|
||||||
CREATE INDEX "IDX_Users_State" ON "Users" ("state");
|
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;
|
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;
|
|
||||||
Reference in New Issue
Block a user