Refactor code structure for improved readability and maintainability
Some checks failed
CI / lint (push) Failing after 1m4s
CI / test-backend (push) Has been skipped
CI / test-frontend (push) Has been skipped
CI / test-e2e (push) Has been skipped

This commit is contained in:
2026-02-22 18:18:46 +01:00
parent c27e9bec7a
commit 0c9c408564
98 changed files with 8207 additions and 5250 deletions

View File

@@ -1,15 +1,222 @@
# Comparativa de APIs — cobertura, límites, coste y calidad
# APIs del Sistema — Guía completa
**Introducción**
Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots, géneros, desarrolladores), y datos de precio/ofertas. Las decisiones de integración deben priorizar cobertura, coste (preferencia: gratuito), calidad y facilidad de uso.
**Nota:** límites y condiciones pueden cambiar — verificar TOS antes de integración.
Este documento integra toda la información sobre APIs del sistema: obtención de claves, prioridades, estrategias, comparación y configuración.
---
## Resumen por API
## Tabla de Contenidos
### IGDB (Internet Games Database)
1. [APIs priorizadas (MVP)](#apis-priorizadas-mvp)
2. [Obtención de claves](#obtención-de-claves)
3. [Guía de integración](#guía-de-integración)
4. [Comparación detallada](#comparación-detallada)
5. [Estrategias técnicas](#estrategias-técnicas)
6. [Configuración y despliegue](#configuración-y-despliegue)
---
## APIs priorizadas (MVP)
### Prioridad Alta
1. **IGDB (Internet Game Database)** - Calidad superior, amplia cobertura
2. **RAWG (Rawg.io)** - Buena cobertura, datos de tiendas
### Prioridad Media
3. **TheGamesDB** - Artwork comunitario
4. **ScreenScraper** - Media específica para ROMs
### Prioridad Baja (para futuras versiones)
5. **PriceCharting** - Precios físicos
6. **IsThereAnyDeal** - Ofertas digitales
7. **MobyGames** - Datos históricos detallados
8. **eBay** - Datos de mercado
---
## Obtención de claves
### IGDB (Internet Game Database)
IGDB usa **OAuth 2.0 via Twitch**. Steps:
1. Go to [Twitch Developer Console](https://dev.twitch.tv/console/apps)
2. Sign in with your Twitch account (create one if needed)
3. Click "Create Application"
- Name: "Quasar" (or your app name)
- Category: Select relevant category
- Accept terms, click Create
4. You'll see:
- **Client ID** — Copy this
- Click "New Secret" to generate **Client Secret** — Copy this
5. Go to Settings → OAuth Redirect URLs
- Add: `http://localhost:3000/oauth/callback` (development)
- For production: `https://yourdomain.com/oauth/callback`
6. In your `.env` file:
```
IGDB_CLIENT_ID=your_client_id
IGDB_CLIENT_SECRET=your_client_secret
```
7. Start Quasar, it will use IGDB automatically
**Rate Limit:** 4 requests/second
### RAWG (Rawg.io)
RAWG has a simpler **API Key** approach:
1. Go to [RAWG Settings](https://rawg.io/settings/account)
2. Sign up if needed, then login
3. Find "API Key" section
4. Click "Create new key" (if needed) or copy existing key
5. In your `.env` file:
```
RAWG_API_KEY=your_api_key_here
```
6. Start Quasar
**Rate Limit:** 20 requests/second (free tier)
**Note:** RAWG requires attribution in UI (include "Powered by RAWG" somewhere visible)
### TheGamesDB (thegamesdb.net)
TheGamesDB uses a simple **API Key**:
1. Go to [TheGamesDB API](https://thegamesdb.net/api)
2. Find "API Key" section (free registration required)
3. Register or login
4. Copy your API key
5. In your `.env` file:
```
THEGAMESDB_API_KEY=your_api_key_here
```
6. Start Quasar
**Rate Limit:** 1 request/second (free tier)
### ScreenScraper
ScreenScraper requiere cuenta y modelo de donación:
1. Go to [ScreenScraper](https://www.screenscraper.fr/)
2. Create account
3. Niveles de donación ofrecen límites distintos (ej.: 50.000 scrapes/día en nivel Bronze)
4. En tu `.env` file:
```
SCREENSCRAPER_USERNAME=your_username
SCREENSCRAPER_PASSWORD=your_password
```
---
## Guía de integración
### IGDB
- **Obtener credenciales**: registrar una app en Twitch Developer Console para obtener `CLIENT_ID` y `CLIENT_SECRET`. Obtener token con grant type `client_credentials` (POST a `https://id.twitch.tv/oauth2/token`).
- **Endpoints principales**: `POST https://api.igdb.com/v4/games` (consulta flexible via body con sintaxis IGDB), `POST https://api.igdb.com/v4/covers`, `POST https://api.igdb.com/v4/platforms`.
- **Ejemplo (buscar)**:
```bash
# Obtener token
curl -X POST 'https://id.twitch.tv/oauth2/token?client_id=$IGDB_CLIENT_ID&client_secret=$IGDB_CLIENT_SECRET&grant_type=client_credentials'
# Buscar juegos
curl -X POST 'https://api.igdb.com/v4/games' \
-H "Client-ID: $IGDB_CLIENT_ID" \
-H "Authorization: Bearer $IGDB_TOKEN" \
-H 'Accept: application/json' \
--data 'fields id,name,first_release_date,platforms.name,genres.name,cover.url; search "zelda"; limit 5;'
```
- **Respuesta (esquemática)**:
```json
[
{
"id": 12345,
"name": "Ejemplo",
"first_release_date": 1459468800,
"platforms": [{ "name": "Nintendo Switch" }],
"cover": { "url": "//images.igdb.com/...jpg" }
}
]
```
- **Límites y manejo**: la API puede devolver `429` o cabeceras de límite; implementar retries exponenciales (ej. 3 intentos) y respetar `Retry-After`. Implementar circuit breaker si la API falla repetidamente.
- **Atribución**: mostrar origen de datos (ej. "Datos: IGDB") según términos del servicio.
### RAWG
- **Obtener credenciales**: registrarse en RAWG para obtener `RAWG_API_KEY` (https://rawg.io/apidocs).
- **Endpoints principales**: `GET https://api.rawg.io/api/games?key=API_KEY&search=...`, `GET https://api.rawg.io/api/games/{id}`.
- **Ejemplo**:
```bash
curl 'https://api.rawg.io/api/games?key=$RAWG_API_KEY&search=zelda&page_size=5'
```
- **Respuesta (esquemática)**:
```json
{
"count": 100,
"results": [
{ "id": 3498, "name": "GTA V", "released": "2013-09-17", "background_image": "https://..." }
]
}
```
- **Límites y manejo**: RAWG suele tener límites por clave/plan; cachear y fallback a otros proveedores si falla.
- **Atribución**: revisar condiciones y mostrar HTTP o texto de fuente si es requerido por el proveedor.
### TheGamesDB
- **Obtener credenciales**: crear cuenta y generar API Key en https://thegamesdb.net.
- **Endpoints**: búsqueda por nombre y detalles (`/v1/Games/ByGameName?name=...`, `/v1/Games/ByGameID?id=...`).
- **Ejemplo**:
```bash
curl -H 'Authorization: Bearer $THEGAMESDB_KEY' 'https://api.thegamesdb.net/v1/Games/ByGameName?name=zelda'
```
### Estrategia de fallback y normalización
- **Orden de prioridad**: IGDB → RAWG → TheGamesDB (configurable).
- **Normalización (mapping)**:
- `title``name`
- `platform``platforms[].name`
- `release_date``first_release_date` / `released` → convertir a ISO 8601
- `genres``genres[].name`
- `cover_url``cover.url` / `background_image`
- `external_ids``{ igdb: id, rawg: id, thegamesdb: id }`
- **Fallback**: si IGDB no tiene portada, intentar RAWG; si falla, usar TheGamesDB. Registrar la fuente usada.
### Caché y almacenamiento de artwork
- **Caché metadata**: LRU en memoria o Redis con TTL (por ejemplo 24h) para evitar sobrecargar APIs.
- **Almacenamiento de imágenes**: descargar y optimizar con `sharp` (crear versiones: thumb, medium), almacenar en `storage/artwork/{gameId}/cover.jpg` o S3.
- **Servicio proxy**: servir imágenes desde backend para no exponer keys ni URLs externas.
### Manejo de errores y resiliencia
- Implementar **retries** exponenciales con jitter (3 intentos).
- Implementar **circuit breaker** para desconectar llamadas a un proveedor fuera de servicio por N minutos.
- Limitar concurrencia por proveedor (p. ej. 5 llamadas simultáneas) y usar colas para trabajos masivos (enriquecimiento masivo).
---
## Comparación detallada
### Resumen por API
#### IGDB (Internet Games Database)
- **Resumen:** Base de datos muy completa (propiedad de Twitch/Amazon) con endpoints para juegos, covers, screenshots, plataformas, ratings, compañías y más.
- **Autenticación / Requisitos:** OAuth vía Twitch (Client ID + Client Secret → token) — requiere cuenta Twitch y 2FA para registrar apps.
@@ -21,9 +228,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Costes / modelo:** Gratuito para uso no comercial; acuerdos comerciales para partners (atribución en caso de partnership).
- **Enlace:** https://api-docs.igdb.com/
---
### RAWG
#### RAWG
- **Resumen:** Gran base de datos (medio millón de juegos), buena para metadata general y enlaces a tiendas.
- **Autenticación / Requisitos:** API key en query string (`key=YOUR_API_KEY`).
@@ -35,9 +240,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Costes / modelo:** Free tier para proyectos personales; planes comerciales (pago mensual) para uso en productos con gran tráfico.
- **Enlace:** https://rawg.io/apidocs
---
### TheGamesDB
#### TheGamesDB
- **Resumen:** Base de datos comunitaria para juegos y artwork, con API pública v2.
- **Autenticación / Requisitos:** Registro y uso de API key (ver docs); repositorio público del proyecto (GPLv3 para el código del servidor).
@@ -48,9 +251,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Cláusula clave:** No documentado públicamente — verificar con el equipo de TheGamesDB antes de uso comercial/redistribución.
- **Enlace:** https://api.thegamesdb.net/
---
### ScreenScraper
#### ScreenScraper
- **Resumen:** Servicio francés orientado a frontends, con enorme cantidad de media y opciones de scraping.
- **Autenticación / Requisitos:** Cuenta en ScreenScraper; modelo de soporte/donación que habilita límites mayores.
@@ -62,9 +263,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Costes / modelo:** Donación / suscripción para aumentar cuotas y velocidad.
- **Enlace:** https://www.screenscraper.fr/
---
### MobyGames
#### MobyGames
- **Resumen:** Base histórica con screenshots, covers, reviews y credits; muy usada por investigación y metadata profunda.
- **Autenticación / Requisitos:** API y/o MobyPlus; la API requiere registro y suscripción.
@@ -76,9 +275,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Costes / modelo:** Acceso vía suscripción / MobyPro; contactar para condiciones comerciales.
- **Enlace:** https://www.mobygames.com/api/subscribe/
---
### PriceCharting
#### PriceCharting
- **Resumen:** Fuente especializada en historial de precios para juegos físicos y coleccionables.
- **Autenticación / Requisitos:** API documentada en el sitio; el acceso completo requiere suscripción / token pagado.
@@ -90,9 +287,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Costes / modelo:** Servicio comercial (licencias / API keys pagadas).
- **Enlace:** https://www.pricecharting.com/api-documentation
---
### IsThereAnyDeal (Itad)
#### IsThereAnyDeal (Itad)
- **Resumen:** Agregador de ofertas con histórico y mapeo de keys/tiendas; útil para tracking de ofertas digitales.
- **Autenticación / Requisitos:** API Key (docs en https://docs.isthereanydeal.com/).
@@ -104,9 +299,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Costes / modelo:** Free tier; acuerdos comerciales para uso intensivo.
- **Enlace:** https://docs.isthereanydeal.com/
---
### eBay
#### eBay
- **Resumen:** Fuente de datos de mercado (listings, precios vendidos) para estimar valor real de mercado.
- **Autenticación / Requisitos:** Registro en eBay Developers Program; claves y OAuth para endpoints de venta/completed items.
@@ -118,9 +311,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
- **Costes / modelo:** Free para desarrolladores con límites; uso intensivo o comerciales pueden requerir acuerdos o certificaciones.
- **Enlace:** https://developer.ebay.com/
---
## Tabla resumida
### Tabla resumida
| API | Data types | Auth | Free / Paid | Fecha verificación | Licencia / Nota legal | Notes |
| -------------- | ------------------------------------------------------- | -------------------------------- | ------------------------------------------ | ------------------ | ------------------------------------------------------------------------------------------------------- | -------------------------------------------------------------- |
@@ -133,9 +324,7 @@ Comparar APIs públicas y comerciales que aportan metadatos (covers, screenshots
| MobyGames | screenshots, credits, covers | Subscribe / API key | Paid / subscription | 2026-02-07 | Paid/Subscribe: https://www.mobygames.com/api/subscribe/ | Access via subscription; non-commercial rate limits documented |
| eBay | listings, sold data | eBay Dev keys / OAuth | Free (with limits) | 2026-02-07 | TOS: https://developer.ebay.com/ | Terms restrict distribution; API License Agreement |
---
## Conclusión y recomendación para MVP
### Conclusión y recomendación para MVP
Recomiendo un **set inicial de APIs (priorizado)**: **IGDB, RAWG, TheGamesDB, ScreenScraper, PriceCharting, IsThereAnyDeal.**
@@ -144,13 +333,171 @@ Recomiendo un **set inicial de APIs (priorizado)**: **IGDB, RAWG, TheGamesDB, Sc
---
## Vacíos y verificación pendiente
## Estrategias técnicas
- **APIs que requieren suscripción / acuerdos comerciales:** PriceCharting (API premium, requiere suscripción), MobyGames (MobyPro/API requiere suscripción), EmuMovies (servicio comercial con TOS y cuentas), y en casos especiales eBay (certificaciones / acuerdos adicionales para ciertos permisos).
- **PriceCharting:** la documentación de la API existe pero el acceso completo está sujeto a registro/pago; no se publicó límite público durante la verificación.
- **MobyGames:** API y límites requieren suscripción/registro; hay que contactar para condiciones comerciales.
- **eBay:** múltiples APIs y límites por endpoint; requiere revisar caso de uso específico y cumplimiento del API License Agreement.
- **Notas:** Algunas APIs (ScreenScraper) usan modelos por donación/premium para aumentar cuotas; en APIs sin límites públicos, contactar al proveedor para confirmar condiciones.
### Variables de entorno (ejemplos)
```
IGDB_CLIENT_ID=...
IGDB_CLIENT_SECRET=...
RAWG_API_KEY=...
THEGAMESDB_API_KEY=...
SCREENSCRAPER_USERNAME=...
SCREENSCRAPER_PASSWORD=...
EXTERNAL_API_CONCURRENCY=5
```
> Nota: **Nunca** exponer estas claves en el cliente; siempre pasar por el backend.
### Normalización de datos
```typescript
interface NormalizedGame {
title: string;
platform: string;
release_date: string; // ISO 8601
genres: string[];
cover_url: string;
external_ids: {
igdb?: string;
rawg?: string;
thegamesdb?: string;
};
source: 'igdb' | 'rawg' | 'thegamesdb' | 'screenscraper';
}
```
### Ejemplo de implementación
```typescript
class MetadataService {
private apis = [
new IGDBService(),
new RAWGService(),
new TheGamesDBService(),
new ScreenScraperService(),
];
async searchGame(title: string): Promise<NormalizedGame> {
for (const api of this.apis) {
try {
const result = await api.search(title);
if (result) {
return this.normalize(result, api.getSource());
}
} catch (error) {
console.warn(`${api.getSource()} failed:`, error);
continue;
}
}
throw new Error('All APIs failed');
}
private normalize(data: any, source: string): NormalizedGame {
return {
title: data.name || data.title,
platform: data.platforms?.[0]?.name || '',
release_date: this.normalizeDate(data.first_release_date || data.released),
genres: data.genres?.map((g: any) => g.name) || [],
cover_url: data.cover?.url || data.background_image || '',
external_ids: {
igdb: data.id,
rawg: data.id,
thegamesdb: data.id,
},
source: source as any,
};
}
}
```
---
## Configuración y despliegue
### Testing Without Real Keys
Para desarrollo/testing:
- Dejar API keys como `your_*_here` en `.env.local`
- Quasar will gracefully degrade and show limited metadata
- Frontend will still work with manual game entry
### Production Deployment
Para producción:
1. Generar nuevas claves en cada servicio (no reutilizar claves de desarrollo)
2. Almacenar claves en **Gitea Secrets** (para pipelines CI/CD automatizados)
3. O usar variables de entorno en tu proveedor de hosting
4. Rotar claves cada 3 meses
5. Monitorear límites de rate en los dashboards de los servicios
### Gitea Actions CI/CD Setup
Para habilitar pruebas automatizadas con API keys en Gitea Actions:
#### 1. Store Secrets in Gitea
Navigate to your repository settings:
```
https://your-gitea-instance/your-org/quasar/settings/secrets/actions
```
Add these secrets:
- `IGDB_CLIENT_ID` (from Twitch Developer Console)
- `IGDB_CLIENT_SECRET` (from Twitch Developer Console)
- `RAWG_API_KEY` (from RAWG settings)
- `THEGAMESDB_API_KEY` (from TheGamesDB API)
- `SCREENSCRAPER_USERNAME` (from ScreenScraper)
- `SCREENSCRAPER_PASSWORD` (from ScreenScraper)
#### 2. Workflow Configuration
The `.gitea/workflows/ci.yml` workflow automatically:
- ✅ Installs dependencies
- ✅ Runs linting checks
- ✅ Executes backend tests (Vitest)
- ✅ Executes frontend tests (Vitest)
- ✅ Starts backend + frontend servers
- ✅ Runs E2E tests (Playwright) with real metadata APIs
- ✅ Uploads test reports on failure
#### 3. Testing Flow
1. **Push** code to `main` or `develop`
2. **Gitea Actions** picks up the `.gitea/workflows/ci.yml`
3. **Secrets are injected** as environment variables
4. **E2E tests** fetch real metadata from APIs (using injected secrets)
5. **Build fails** if any test fails (prevents broken code)
#### 4. Local Development
For local testing, use `.env.local`:
```bash
IGDB_CLIENT_ID=your_local_id
IGDB_CLIENT_SECRET=your_local_secret
RAWG_API_KEY=your_local_key
THEGAMESDB_API_KEY=your_local_key
SCREENSCRAPER_USERNAME=your_username
SCREENSCRAPER_PASSWORD=your_password
```
**Note:** CI/CD uses Gitea Secrets (not `.env` files), so never commit real credentials.
### Troubleshooting
**"IGDB_CLIENT_ID not found"** → Check `.env` file exists and has correct format
**"429 Too Many Requests"** → Rate limit exceeded, wait and retry
**"Invalid API Key"** → Copy key exactly (no spaces), verify it's active on service website
**"ScreenScraper authentication failed"** → Check donation level and account status
---

1195
docs/02-tecnico/frontend.md Normal file

File diff suppressed because it is too large Load Diff

View 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_

View File

@@ -1,140 +0,0 @@
# Obtaining API Keys
This guide explains how to get credentials for each metadata service.
## IGDB (Internet Game Database)
IGDB uses **OAuth 2.0 via Twitch**. Steps:
1. Go to [Twitch Developer Console](https://dev.twitch.tv/console/apps)
2. Sign in with your Twitch account (create one if needed)
3. Click "Create Application"
- Name: "Quasar" (or your app name)
- Category: Select relevant category
- Accept terms, click Create
4. You'll see:
- **Client ID** — Copy this
- Click "New Secret" to generate **Client Secret** — Copy this
5. Go to Settings → OAuth Redirect URLs
- Add: `http://localhost:3000/oauth/callback` (development)
- For production: `https://yourdomain.com/oauth/callback`
6. In your `.env` file:
```
IGDB_CLIENT_ID=your_client_id
IGDB_CLIENT_SECRET=your_client_secret
```
7. Start Quasar, it will use IGDB automatically
**Rate Limit:** 4 requests/second
## RAWG (Rawg.io)
RAWG has a simpler **API Key** approach:
1. Go to [RAWG Settings](https://rawg.io/settings/account)
2. Sign up if needed, then login
3. Find "API Key" section
4. Click "Create new key" (if needed) or copy existing key
5. In your `.env` file:
```
RAWG_API_KEY=your_api_key_here
```
6. Start Quasar
**Rate Limit:** 20 requests/second (free tier)
**Note:** RAWG requires attribution in UI (include "Powered by RAWG" somewhere visible)
## TheGamesDB (thegamesdb.net)
TheGamesDB uses a simple **API Key**:
1. Go to [TheGamesDB API](https://thegamesdb.net/api)
2. Find "API Key" section (free registration required)
3. Register or login
4. Copy your API key
5. In your `.env` file:
```
THEGAMESDB_API_KEY=your_api_key_here
```
6. Start Quasar
**Rate Limit:** 1 request/second (free tier)
## Testing Without Real Keys
For development/testing:
- Leave API keys as `your_*_here` in `.env.local`
- Quasar will gracefully degrade and show limited metadata
- Frontend will still work with manual game entry
## Production Deployment
For production:
1. Generate new keys on each service (don't reuse dev keys)
2. Store keys in **Gitea Secrets** (for automated CI/CD pipelines)
3. Or use environment variables on your hosting provider
4. Rotate keys every 3 months
5. Monitor rate limits in service dashboards
## Gitea Actions CI/CD Setup
To enable automated testing with API keys in Gitea Actions:
### 1. Store Secrets in Gitea
Navigate to your repository settings:
```
https://your-gitea-instance/your-org/quasar/settings/secrets/actions
```
Add these secrets:
- `IGDB_CLIENT_ID` (from Twitch Developer Console)
- `IGDB_CLIENT_SECRET` (from Twitch Developer Console)
- `RAWG_API_KEY` (from RAWG settings)
- `THEGAMESDB_API_KEY` (from TheGamesDB API)
### 2. Workflow Configuration
The `.gitea/workflows/ci.yml` workflow automatically:
- ✅ Installs dependencies
- ✅ Runs linting checks
- ✅ Executes backend tests (Vitest)
- ✅ Executes frontend tests (Vitest)
- ✅ Starts backend + frontend servers
- ✅ Runs E2E tests (Playwright) with real metadata APIs
- ✅ Uploads test reports on failure
### 3. Testing Flow
1. **Push** code to `main` or `develop`
2. **Gitea Actions** picks up the `.gitea/workflows/ci.yml`
3. **Secrets are injected** as `IGDB_CLIENT_ID`, `IGDB_CLIENT_SECRET`, `RAWG_API_KEY`, `THEGAMESDB_API_KEY`
4. **E2E tests** fetch real metadata from APIs (using injected secrets)
5. **Build fails** if any test fails (prevents broken code)
### 4. Local Development
For local testing, use `.env.local`:
```bash
IGDB_CLIENT_ID=your_local_id
IGDB_CLIENT_SECRET=your_local_secret
RAWG_API_KEY=your_local_key
THEGAMESDB_API_KEY=your_local_key
```
**Note:** CI/CD uses Gitea Secrets (not `.env` files), so never commit real credentials.
## Troubleshooting
**"IGDB_CLIENT_ID not found"** → Check `.env` file exists and has correct format
**"429 Too Many Requests"** → Rate limit exceeded, wait and retry
**"Invalid API Key"** → Copy key exactly (no spaces), verify it's active on service website

92
docs/README.md Normal file
View File

@@ -0,0 +1,92 @@
# Documentación del Proyecto Quasar 📚
Esta documentación está organizada en secciones lógicas para facilitar la navegación y mantenimiento.
## Estructura de la Documentación
```
docs/
├── README.md # Este archivo (índice general)
├── 01-conceptos/ # Conceptos fundamentales y requisitos
│ ├── requirements.md # Requisitos funcionales y no funcionales
│ ├── architecture.md # Arquitectura técnica general
│ └── data-model.md # Modelo de datos y esquema
├── 02-tecnico/ # Documentación técnica detallada
│ ├── apis.md # APIs del sistema (consolidado)
│ ├── frontend.md # Documentación del frontend
│ └── lessons-learned.md # Lecciones aprendidas y recomendaciones
├── 03-analisis/ # Análisis comparativos y estudios
│ └── competitive-analysis.md # Análisis competitivo
└── 04-operaciones/ # Guías de operación y despliegue
```
## Guía de Navegación
### 🎯 Para nuevos desarrolladores
1. Comienza con [`01-conceptos/requirements.md`](01-conceptos/requirements.md) para entender el propósito
2. Lee [`01-conceptos/architecture.md`](01-conceptos/architecture.md) para la visión general
3. Revisa [`01-conceptos/data-model.md`](01-conceptos/data-model.md) para entender los datos
### 🔧 Para trabajo técnico
1. Consulta [`02-tecnico/apis.md`](02-tecnico/apis.md) para APIs y configuración
2. Revisa [`02-tecnico/frontend.md`](02-tecnico/frontend.md) para detalles del frontend
3. Lee [`02-tecnico/lessons-learned.md`](02-tecnico/lessons-learned.md) para buenas prácticas
### 📊 Para análisis y decisiones
1. Revisa [`03-analisis/competitive-analysis.md`](03-analisis/competitive-analysis.md) para contexto del mercado
### 🚀 Para operaciones y despliegue
1. Las guías de operación están en desarrollo (sección `04-operaciones/`)
## Convenciones
### Formato de enlaces
Todos los enlaces internos usan formato markdown estándar:
```markdown
[texto de enlace](ruta/al/archivo.md)
```
### Nomenclatura de archivos
- Todos los usan `kebab-case.md`
- Los prefijos numéricos indican orden de lectura
### Estructura de documentos
- Cada documento tiene tabla de contenidos (TOC)
- Secciones numeradas para mejor navegación
- Ejemplos de código con formato sintáctico
## Estado Actual
| Sección | Estado | Comentarios |
| -------------- | ---------------- | ------------------------------------ |
| 01-conceptos | ✅ Completa | Documentación fundamental estable |
| 02-tecnico | ✅ Actualizada | APIs consolidados, frontend completo |
| 03-analisis | ✅ Completa | Análisis competitivo actualizado |
| 04-operaciones | 🚧 En desarrollo | Guías de operación pendientes |
## Próximos Pasos
- [ ] Añadir documentación de testing y CI/CD
- [ ] Crear índice temático para búsqueda rápida
- [ ] Documentar API REST detallada
## Contribuir
Al agregar nuevo contenido:
1. Coloca el documento en la sección adecuada
2. Sigue las convenciones de nomenclatura
3. Actualiza este README si agregas nuevas secciones
4. Revisa y actualiza referencias cruzadas
---
_Última actualización: 2026-02-22_

View File

@@ -1,148 +0,0 @@
# Integración de APIs externas — Prioridad y guía práctica
## Objetivo
Definir APIs prioritarias para el MVP, cómo obtener credenciales, ejemplos de uso y estrategias de robustez (rate limit, retries, fallback y normalización de datos).
---
## APIs priorizadas (MVP)
1. **IGDB (prioridad alta)**
2. **RAWG (prioridad alta)**
3. **TheGamesDB (prioridad media)**
---
## IGDB
- **Obtener credenciales**: registrar una app en Twitch Developer Console para obtener `CLIENT_ID` y `CLIENT_SECRET`. Obtener token con grant type `client_credentials` (POST a `https://id.twitch.tv/oauth2/token`).
- **Endpoints principales**: `POST https://api.igdb.com/v4/games` (consulta flexible via body con sintaxis IGDB), `POST https://api.igdb.com/v4/covers`, `POST https://api.igdb.com/v4/platforms`.
- **Ejemplo (buscar)**:
```bash
# Obtener token
curl -X POST 'https://id.twitch.tv/oauth2/token?client_id=$IGDB_CLIENT_ID&client_secret=$IGDB_CLIENT_SECRET&grant_type=client_credentials'
# Buscar juegos
curl -X POST 'https://api.igdb.com/v4/games' \
-H "Client-ID: $IGDB_CLIENT_ID" \
-H "Authorization: Bearer $IGDB_TOKEN" \
-H 'Accept: application/json' \
--data 'fields id,name,first_release_date,platforms.name,genres.name,cover.url; search "zelda"; limit 5;'
```
- **Respuesta (esquemática)**:
```json
[
{
"id": 12345,
"name": "Ejemplo",
"first_release_date": 1459468800,
"platforms": [{ "name": "Nintendo Switch" }],
"cover": { "url": "//images.igdb.com/...jpg" }
}
]
```
- **Límites y manejo**: la API puede devolver `429` o cabeceras de límite; implementar retries exponenciales (ej. 3 intentos) y respetar `Retry-After`. Implementar circuit breaker si la API falla repetidamente.
- **Atribución**: mostrar origen de datos (ej. "Datos: IGDB") según términos del servicio.
---
## RAWG
- **Obtener credenciales**: registrarse en RAWG para obtener `RAWG_API_KEY` (https://rawg.io/apidocs).
- **Endpoints principales**: `GET https://api.rawg.io/api/games?key=API_KEY&search=...`, `GET https://api.rawg.io/api/games/{id}`.
- **Ejemplo**:
```bash
curl 'https://api.rawg.io/api/games?key=$RAWG_API_KEY&search=zelda&page_size=5'
```
- **Respuesta (esquemática)**:
```json
{
"count": 100,
"results": [
{ "id": 3498, "name": "GTA V", "released": "2013-09-17", "background_image": "https://..." }
]
}
```
- **Límites y manejo**: RAWG suele tener límites por clave/plan; cachear y fallback a otros proveedores si falla.
- **Atribución**: revisar condiciones y mostrar HTTP o texto de fuente si es requerido por el proveedor.
---
## TheGamesDB
- **Obtener credenciales**: crear cuenta y generar API Key en https://thegamesdb.net.
- **Endpoints**: búsqueda por nombre y detalles (`/v1/Games/ByGameName?name=...`, `/v1/Games/ByGameID?id=...`).
- **Ejemplo**:
```bash
curl -H 'Authorization: Bearer $THEGAMESDB_KEY' 'https://api.thegamesdb.net/v1/Games/ByGameName?name=zelda'
```
---
## Estrategia de fallback y normalización
- **Orden de prioridad**: IGDB → RAWG → TheGamesDB (configurable).
- **Normalización (mapping)**:
- `title``name`
- `platform``platforms[].name`
- `release_date``first_release_date` / `released` → convertir a ISO 8601
- `genres``genres[].name`
- `cover_url``cover.url` / `background_image`
- `external_ids``{ igdb: id, rawg: id, thegamesdb: id }`
- **Fallback**: si IGDB no tiene portada, intentar RAWG; si falla, usar TheGamesDB. Registrar la fuente usada.
---
## Caché y almacenamiento de artwork
- **Caché metadata**: LRU en memoria o Redis con TTL (por ejemplo 24h) para evitar sobrecargar APIs.
- **Almacenamiento de imágenes**: descargar y optimizar con `sharp` (crear versiones: thumb, medium), almacenar en `storage/artwork/{gameId}/cover.jpg` o S3.
- **Servicio proxy**: servir imágenes desde backend para no exponer keys ni URLs externas.
---
## Manejo de errores y resiliencia
- Implementar **retries** exponenciales con jitter (3 intentos).
- Implementar **circuit breaker** para desconectar llamadas a un proveedor fuera de servicio por N minutos.
- Limitar concurrencia por proveedor (p. ej. 5 llamadas simultáneas) y usar colas para trabajos masivos (enriquecimiento masivo).
---
## Variables de entorno (ejemplos)
```
IGDB_CLIENT_ID=...
IGDB_CLIENT_SECRET=...
RAWG_API_KEY=...
THEGAMESDB_API_KEY=...
EXTERNAL_API_CONCURRENCY=5
```
> Nota: **Nunca** exponer estas claves en el cliente; siempre pasar por el backend.
---
## Fuentes
- IGDB API docs, RAWG API docs, TheGamesDB API docs.
- Patrones: retries, circuit breakers (ej. libraries: `p-retry`, `cockatiel`).
---
**Metadatos**
Autor: Quasar (investigación automatizada)
Última actualización: 2026-02-07