Refactor code structure for improved readability and maintainability
This commit is contained in:
546
docs/04-operaciones/deployment.md
Normal file
546
docs/04-operaciones/deployment.md
Normal file
@@ -0,0 +1,546 @@
|
||||
# Guía de Despliegue y Operaciones 🚀
|
||||
|
||||
Esta guía cubre el despliegue, configuración y operación de Quasar en producción.
|
||||
|
||||
---
|
||||
|
||||
## Tabla de Contenidos
|
||||
|
||||
1. [Requisitos del Sistema](#requisitos-del-sistema)
|
||||
2. [Configuración de Producción](#configuración-de-producción)
|
||||
3. [Despliegue](#despliegue)
|
||||
4. [Monitoreo y Mantenimiento](#monitoreo-y-mantenimiento)
|
||||
5. [Actualizaciones](#actualizaciones)
|
||||
6. [Backup y Recuperación](#backup-y-recuperación)
|
||||
7. [Solución de Problemas](#solución-de-problemas)
|
||||
|
||||
---
|
||||
|
||||
## Requisitos del Sistema
|
||||
|
||||
### Hardware Mínimo
|
||||
|
||||
- **CPU:** 2 cores
|
||||
- **RAM:** 4GB
|
||||
- **Almacenamiento:** 20GB (para ROMs y metadata)
|
||||
- **Red:** Estable (para descargas de artwork)
|
||||
|
||||
### Software
|
||||
|
||||
- **Node.js 18+**
|
||||
- **Yarn 4.x**
|
||||
- **SQLite** (o PostgreSQL para producción)
|
||||
- **Nginx** (recomendado para reverse proxy)
|
||||
- **Certificado SSL** (HTTPS obligatorio)
|
||||
|
||||
### Dependencias Externas
|
||||
|
||||
- Claves API de IGDB, RAWG, TheGamesDB
|
||||
- Acceso a servicios de descarga de imágenes
|
||||
|
||||
---
|
||||
|
||||
## Configuración de Producción
|
||||
|
||||
### Variables de Entorno
|
||||
|
||||
Crear `.env.production` con:
|
||||
|
||||
```env
|
||||
# Database
|
||||
DATABASE_URL="file:./production.db"
|
||||
# Para PostgreSQL: postgresql://user:password@localhost:5432/quasar
|
||||
|
||||
# API Keys
|
||||
IGDB_CLIENT_ID=your_production_client_id
|
||||
IGDB_CLIENT_SECRET=your_production_client_secret
|
||||
RAWG_API_KEY=your_production_api_key
|
||||
THEGAMESDB_API_KEY=your_production_api_key
|
||||
SCREENSCRAPER_USERNAME=your_screenscraper_username
|
||||
SCREENSCRAPER_PASSWORD=your_screenscraper_password
|
||||
|
||||
# App Config
|
||||
NODE_ENV=production
|
||||
PORT=3000
|
||||
HOST=0.0.0.0
|
||||
LOG_LEVEL=info
|
||||
|
||||
# Security
|
||||
CORS_ORIGIN=https://yourdomain.com
|
||||
JWT_SECRET=your_secure_jwt_secret_here
|
||||
API_RATE_LIMIT=100
|
||||
|
||||
# Performance
|
||||
CACHE_TTL=86400
|
||||
MAX_CONCURRENT_API_REQUESTS=5
|
||||
```
|
||||
|
||||
### Configuración de Nginx
|
||||
|
||||
```nginx
|
||||
server {
|
||||
listen 443 ssl http2;
|
||||
server_name yourdomain.com;
|
||||
|
||||
# SSL Configuration
|
||||
ssl_certificate /path/to/cert.pem;
|
||||
ssl_certificate_key /path/to/key.pem;
|
||||
ssl_protocols TLSv1.2 TLSv1.3;
|
||||
|
||||
# Security headers
|
||||
add_header X-Frame-Options DENY;
|
||||
add_header X-Content-Type-Options nosniff;
|
||||
add_header X-XSS-Protection "1; mode=block";
|
||||
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
|
||||
|
||||
# Frontend
|
||||
location / {
|
||||
root /var/www/quasar/frontend/dist;
|
||||
try_files $uri $uri/ /index.html;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
|
||||
# Backend API
|
||||
location /api/ {
|
||||
proxy_pass http://localhost:3000;
|
||||
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_cache_bypass $http_upgrade;
|
||||
proxy_read_timeout 864s;
|
||||
}
|
||||
|
||||
# Static files
|
||||
location /static/ {
|
||||
root /var/www/quasar;
|
||||
expires 1y;
|
||||
add_header Cache-Control "public, immutable";
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Despliegue
|
||||
|
||||
### Opción 1: Docker (Recomendado)
|
||||
|
||||
```dockerfile
|
||||
# Dockerfile
|
||||
FROM node:18-alpine AS base
|
||||
|
||||
# Install dependencies only when needed
|
||||
FROM base AS deps
|
||||
RUN apk add --no-cache libc6-compat
|
||||
WORKDIR /app
|
||||
|
||||
# Install dependencies based on the preferred package manager
|
||||
COPY package.json yarn.lock* ./
|
||||
RUN yarn install --frozen-lockfile
|
||||
|
||||
# Rebuild the source code only when needed
|
||||
FROM base AS builder
|
||||
WORKDIR /app
|
||||
COPY --from=deps /app/node_modules ./node_modules
|
||||
COPY . .
|
||||
|
||||
# Build the application
|
||||
RUN yarn build
|
||||
|
||||
# Production image, copy all the files and run next
|
||||
FROM base AS runner
|
||||
WORKDIR /app
|
||||
|
||||
ENV NODE_ENV=production
|
||||
ENV PORT=3000
|
||||
|
||||
# Copy built application
|
||||
COPY --from=builder /app/dist ./dist
|
||||
COPY --from=builder /app/node_modules ./node_modules
|
||||
COPY --from=builder /app/package.json ./package.json
|
||||
|
||||
# Create non-root user
|
||||
RUN addgroup --system --gid 1001 nodejs
|
||||
RUN adduser --system --uid 1001 nextjs
|
||||
|
||||
USER nextjs
|
||||
|
||||
EXPOSE 3000
|
||||
|
||||
CMD ["node", "dist/server.js"]
|
||||
```
|
||||
|
||||
```yaml
|
||||
# docker-compose.yml
|
||||
version: '3.8'
|
||||
|
||||
services:
|
||||
quasar-backend:
|
||||
build: ./backend
|
||||
ports:
|
||||
- '3000:3000'
|
||||
environment:
|
||||
- NODE_ENV=production
|
||||
- DATABASE_URL=file:./production.db
|
||||
- IGDB_CLIENT_ID=${IGDB_CLIENT_ID}
|
||||
- IGDB_CLIENT_SECRET=${IGDB_CLIENT_SECRET}
|
||||
- RAWG_API_KEY=${RAWG_API_KEY}
|
||||
- THEGAMESDB_API_KEY=${THEGAMESDB_API_KEY}
|
||||
volumes:
|
||||
- ./data:/app/data
|
||||
- ./backend/prisma:/app/prisma
|
||||
restart: unless-stopped
|
||||
|
||||
quasar-frontend:
|
||||
build: ./frontend
|
||||
ports:
|
||||
- '5173:5173'
|
||||
depends_on:
|
||||
- quasar-backend
|
||||
restart: unless-stopped
|
||||
|
||||
nginx:
|
||||
image: nginx:alpine
|
||||
ports:
|
||||
- '443:443'
|
||||
volumes:
|
||||
- ./nginx.conf:/etc/nginx/nginx.conf
|
||||
- ./ssl:/etc/nginx/ssl
|
||||
depends_on:
|
||||
- quasar-backend
|
||||
- quasar-frontend
|
||||
restart: unless-stopped
|
||||
```
|
||||
|
||||
### Opción 2: VPS Manual
|
||||
|
||||
```bash
|
||||
# 1. Setup server
|
||||
sudo apt update
|
||||
sudo apt install -y nodejs yarn nginx sqlite3
|
||||
|
||||
# 2. Clone repository
|
||||
git clone https://your-repo/quasar.git
|
||||
cd quasar
|
||||
|
||||
# 3. Install dependencies
|
||||
yarn install --production
|
||||
|
||||
# 4. Setup environment
|
||||
cp .env.example .env.production
|
||||
# Edit .env.production with real values
|
||||
|
||||
# 5. Build frontend
|
||||
cd frontend
|
||||
yarn build
|
||||
cd ..
|
||||
|
||||
# 6. Setup database
|
||||
cd backend
|
||||
npx prisma migrate deploy
|
||||
cd ..
|
||||
|
||||
# 7. Configure nginx
|
||||
sudo cp nginx.conf /etc/nginx/sites-available/quasar
|
||||
sudo ln -s /etc/nginx/sites-available/quasar /etc/nginx/sites-enabled/
|
||||
sudo nginx -t
|
||||
sudo systemctl reload nginx
|
||||
|
||||
# 8. Start services
|
||||
cd backend
|
||||
nohup yarn start > /var/log/quasar-backend.log 2>&1 &
|
||||
cd ../frontend
|
||||
nohup yarn start > /var/log/quasar-frontend.log 2>&1 &
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Monitoreo y Mantenimiento
|
||||
|
||||
### Health Checks
|
||||
|
||||
```bash
|
||||
# Backend health
|
||||
curl http://localhost:3000/health
|
||||
|
||||
# Database connection
|
||||
curl http://localhost:3000/api/health/database
|
||||
|
||||
# API rate limits status
|
||||
curl http://localhost:3000/api/health/rate-limits
|
||||
```
|
||||
|
||||
### Logging
|
||||
|
||||
Configurar logrotate:
|
||||
|
||||
```bash
|
||||
# /etc/logrotate.d/quasar
|
||||
/var/log/quasar/*.log {
|
||||
daily
|
||||
missingok
|
||||
rotate 7
|
||||
compress
|
||||
delaycompress
|
||||
notifempty
|
||||
copytruncate
|
||||
}
|
||||
```
|
||||
|
||||
### Monitoreo de API Keys
|
||||
|
||||
Crear script para verificar límites:
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# check-api-limits.sh
|
||||
|
||||
# Check IGDB rate limits
|
||||
curl -s -I "https://api.igdb.com/v4/games" | grep -i "x-ratelimit"
|
||||
|
||||
# Check RAWG usage
|
||||
curl -s "https://api.rawg.io/api/games?key=$RAWG_API_KEY&search=test" | jq '.count'
|
||||
|
||||
# Log warnings
|
||||
echo "$(date): API rate limits checked" >> /var/log/quasar/api-monitor.log
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Actualizaciones
|
||||
|
||||
### Proceso de Actualización
|
||||
|
||||
```bash
|
||||
# 1. Backup
|
||||
./backup.sh
|
||||
|
||||
# 2. Stop services
|
||||
sudo systemctl stop quasar-backend
|
||||
sudo systemctl stop quasar-frontend
|
||||
|
||||
# 3. Pull latest code
|
||||
git pull origin main
|
||||
|
||||
# 4. Update dependencies
|
||||
yarn install --frozen-lockfile
|
||||
|
||||
# 5. Build frontend
|
||||
cd frontend && yarn build && cd ..
|
||||
|
||||
# 6. Run migrations
|
||||
cd backend && npx prisma migrate deploy && cd ..
|
||||
|
||||
# 7. Start services
|
||||
sudo systemctl start quasar-backend
|
||||
sudo systemctl start quasar-frontend
|
||||
```
|
||||
|
||||
### Actualizaciones de API Keys
|
||||
|
||||
1. Generar nuevas claves en cada servicio
|
||||
2. Actualizar variables de entorno
|
||||
3. Reiniciar servicios
|
||||
4. Monitorear errores durante 24h
|
||||
|
||||
---
|
||||
|
||||
## Backup y Recuperación
|
||||
|
||||
### Script de Backup
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# backup.sh
|
||||
|
||||
BACKUP_DIR="/backups/quasar"
|
||||
DATE=$(date +%Y%m%d_%H%M%S)
|
||||
DB_FILE="quasar_$DATE.db"
|
||||
ROMS_DIR="roms_$DATE"
|
||||
|
||||
# Create backup directory
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
|
||||
# Backup database
|
||||
cp backend/prisma/production.db "$BACKUP_DIR/$DB_FILE"
|
||||
|
||||
# Backup ROM metadata (not actual ROMs)
|
||||
cp -r data/roms_metadata "$BACKUP_DIR/$ROMS_DIR"
|
||||
|
||||
# Backup configuration
|
||||
cp .env.production "$BACKUP_DIR/env_$DATE"
|
||||
|
||||
# Compress backup
|
||||
tar -czf "$BACKUP_DIR/backup_$DATE.tar.gz" -C "$BACKUP_DIR" "$DB_FILE" "$ROMS_DIR" "env_$DATE"
|
||||
|
||||
# Clean up old backups (keep last 7 days)
|
||||
find "$BACKUP_DIR" -name "backup_*.tar.gz" -mtime +7 -delete
|
||||
|
||||
echo "Backup completed: $BACKUP_DIR/backup_$DATE.tar.gz"
|
||||
```
|
||||
|
||||
### Recuperación
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
# restore.sh
|
||||
|
||||
BACKUP_FILE=$1
|
||||
BACKUP_DIR="/backups/quasar"
|
||||
|
||||
if [ ! -f "$BACKUP_DIR/$BACKUP_FILE" ]; then
|
||||
echo "Backup file not found: $BACKUP_DIR/$BACKUP_FILE"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Stop services
|
||||
sudo systemctl stop quasar-backend
|
||||
sudo systemctl stop quasar-frontend
|
||||
|
||||
# Extract backup
|
||||
cd "$BACKUP_DIR"
|
||||
tar -xzf "$BACKUP_FILE"
|
||||
|
||||
# Restore database
|
||||
cp "$DB_FILE" backend/prisma/production.db
|
||||
|
||||
# Restore ROM metadata
|
||||
cp -r "$ROMS_DIR"/* data/
|
||||
|
||||
# Restore configuration (optional)
|
||||
# cp "env_$DATE" .env.production
|
||||
|
||||
# Start services
|
||||
sudo systemctl start quasar-backend
|
||||
sudo systemctl start quasar-frontend
|
||||
|
||||
echo "Restore completed from: $BACKUP_FILE"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Solución de Problemas
|
||||
|
||||
### Problemas Comunes
|
||||
|
||||
#### 1. "Database connection failed"
|
||||
|
||||
```bash
|
||||
# Check database file
|
||||
ls -la backend/prisma/production.db
|
||||
|
||||
# Check permissions
|
||||
sudo chown -R nodejs:nodejs backend/prisma/
|
||||
|
||||
# Check database integrity
|
||||
sqlite3 backend/prisma/production.db "PRAGMA integrity_check;"
|
||||
```
|
||||
|
||||
#### 2. "API rate limit exceeded"
|
||||
|
||||
```bash
|
||||
# Check current rate limits
|
||||
curl -I "https://api.igdb.com/v4/games" | grep -i "x-ratelimit"
|
||||
|
||||
# Implement backoff strategy
|
||||
# Check logs for specific API errors
|
||||
tail -f /var/log/quasar/backend.log | grep "429"
|
||||
```
|
||||
|
||||
#### 3. "Frontend cannot connect to backend"
|
||||
|
||||
```bash
|
||||
# Check backend is running
|
||||
curl http://localhost:3000/health
|
||||
|
||||
# Check CORS configuration
|
||||
curl -H "Origin: https://yourdomain.com" -v http://localhost:3000/health
|
||||
|
||||
# Check nginx configuration
|
||||
sudo nginx -t
|
||||
```
|
||||
|
||||
#### 4. "ROM scanning fails"
|
||||
|
||||
```bash
|
||||
# Check directory permissions
|
||||
ls -la /path/to/roms/
|
||||
|
||||
# Check file formats
|
||||
find /path/to/roms/ -name "*.zip" -o -name "*.7z" -o -name "*.rar"
|
||||
|
||||
# Check disk space
|
||||
df -h
|
||||
```
|
||||
|
||||
### Diagnóstico Remoto
|
||||
|
||||
```bash
|
||||
# Create diagnostic script
|
||||
#!/bin/bash
|
||||
# diagnostic.sh
|
||||
|
||||
echo "=== Quasar Diagnostic Report ==="
|
||||
echo "Date: $(date)"
|
||||
echo "Node.js version: $(node --version)"
|
||||
echo "Yarn version: $(yarn --version)"
|
||||
echo ""
|
||||
|
||||
echo "=== System Resources ==="
|
||||
free -h
|
||||
df -h
|
||||
echo ""
|
||||
|
||||
echo "=== Services Status ==="
|
||||
systemctl status quasar-backend
|
||||
systemctl status quasar-frontend
|
||||
echo ""
|
||||
|
||||
echo "=== Database Status ==="
|
||||
sqlite3 backend/prisma/production.db "SELECT COUNT(*) FROM games;"
|
||||
sqlite3 backend/prisma/production.db "SELECT COUNT(*) FROM rom_files;"
|
||||
echo ""
|
||||
|
||||
echo "=== API Keys Status ==="
|
||||
echo "IGDB: ${IGDB_CLIENT_ID:0:10}..."
|
||||
echo "RAWG: ${RAWG_API_KEY:0:10}..."
|
||||
echo "TheGamesDB: ${THEGAMESDB_API_KEY:0:10}..."
|
||||
echo ""
|
||||
|
||||
echo "=== Recent Errors ==="
|
||||
tail -20 /var/log/quasar/backend.log | grep -i "error"
|
||||
tail -20 /var/log/quasar/frontend.log | grep -i "error"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Soporte
|
||||
|
||||
### Logs de Depuración
|
||||
|
||||
```bash
|
||||
# Backend logs
|
||||
tail -f /var/log/quasar/backend.log
|
||||
|
||||
# Frontend logs
|
||||
tail -f /var/log/quasar/frontend.log
|
||||
|
||||
# Nginx logs
|
||||
tail -f /var/log/nginx/access.log
|
||||
tail -f /var/log/nginx/error.log
|
||||
```
|
||||
|
||||
### Contacto
|
||||
|
||||
- **Issues:** Reportar en el repositorio de Gitea
|
||||
- **Emergencias:** Email: support@yourdomain.com
|
||||
- **Documentación:** Ver [docs/README.md](../../README.md)
|
||||
|
||||
---
|
||||
|
||||
_Última actualización: 2026-02-22_
|
||||
Reference in New Issue
Block a user