Files
quasar/docs/02-tecnico/game-search.md
Benito Rodríguez 2667e11284
Some checks failed
CI / lint (push) Failing after 10s
CI / test-backend (push) Has been skipped
CI / test-frontend (push) Has been skipped
CI / test-e2e (push) Has been skipped
Refactor code structure for improved readability and maintainability
2026-03-22 11:34:38 +01:00

7.4 KiB

Búsqueda de Juegos

Resumen

La funcionalidad de búsqueda de juegos permite a los usuarios buscar metadatos de juegos desde múltiples fuentes externas (IGDB, RAWG, TheGamesDB) y agregarlos a su biblioteca personal.

Arquitectura

Backend

Endpoints

GET /api/metadata/search

Busca metadatos de juegos en múltiples fuentes externas.

Parámetros de query:

  • q (string, requerido): Término de búsqueda del título del juego
  • platform (string, opcional): Plataforma para filtrar (ej. "NES", "SNES")
  • year (number, opcional): Año de lanzamiento para filtrar (1900-2100)

Respuesta:

interface EnrichedGame {
  source: 'igdb' | 'rawg' | 'thegamesdb';
  externalIds: {
    igdb?: number;
    rawg?: number;
    thegamesdb?: number;
  };
  name: string;
  title: string;
  slug: string;
  releaseDate?: string;
  genres?: string[];
  coverUrl?: string;
  platforms?: PlatformInfo[];
}

Ejemplo de solicitud:

curl "http://localhost:3003/api/metadata/search?q=Sonic&platform=Genesis&year=1991"
POST /api/games/from-metadata

Crea un juego nuevo a partir de metadatos de búsqueda.

Body:

interface CreateGameFromMetadataBody {
  metadata: EnrichedGame;
  overrides?: {
    platformId?: string;
    description?: string;
    priceCents?: number;
    currency?: string;
    store?: string;
    date?: string;
    condition?: 'Loose' | 'CIB' | 'New';
  };
}

Respuesta:

interface Game {
  id: string;
  title: string;
  slug: string;
  description?: string;
  releaseDate?: string;
  genre?: string;
  platform?: string;
  year?: number;
  cover?: string;
  source: string;
  sourceId?: string;
}

Ejemplo de solicitud:

curl -X POST http://localhost:3003/api/games/from-metadata \
  -H "Content-Type: application/json" \
  -d '{
    "metadata": {
      "source": "igdb",
      "externalIds": { "igdb": 12345 },
      "name": "Sonic the Hedgehog",
      "slug": "sonic-the-hedgehog",
      "releaseDate": "1991-06-23",
      "genres": ["Platform"],
      "coverUrl": "https://example.com/cover.jpg"
    },
    "overrides": {
      "description": "Juego clásico de SEGA",
      "condition": "CIB"
    }
  }'

Servicios

metadataService.searchGames()

Orquesta la búsqueda en múltiples fuentes externas.

Parámetros:

interface SearchGamesParams {
  title: string;
  platform?: string;
  year?: number;
}

Respuesta: Array de EnrichedGame[]

Fuentes soportadas:

  • IGDB: Base de datos de videojuegos más completa
  • RAWG: API de videojuegos con datos de múltiples fuentes
  • TheGamesDB: Base de datos comunitaria de videojuegos

Frontend

Página /games/add

Página principal para buscar y agregar juegos a la biblioteca.

Componentes:

SearchForm

Formulario de búsqueda con los siguientes campos:

  • Título (requerido): Campo de texto para el título del juego
  • Plataforma (opcional): Dropdown con plataformas comunes
  • Año (opcional): Campo numérico para filtrar por año

Props:

interface SearchFormProps {
  onSearch: (params: SearchGamesParams) => void;
  isLoading?: boolean;
}
SearchResults

Muestra los resultados de la búsqueda en una lista.

Props:

interface SearchResultsProps {
  results: EnrichedGame[];
  onSelectResult: (result: EnrichedGame) => void;
  isLoading?: boolean;
}

Características:

  • Muestra la portada del juego
  • Muestra el título, año y géneros
  • Indica la fuente de los datos (IGDB, RAWG, TheGamesDB)
  • Botón para seleccionar un resultado
GamePreviewDialog

Dialog modal para previsualizar y editar los metadatos antes de guardar.

Props:

interface GamePreviewDialogProps {
  open: boolean;
  game: EnrichedGame | null;
  onClose: () => void;
  onSave: (data: CreateGameFromMetadataInput) => void;
}

Características:

  • Muestra la portada del juego
  • Campos editables: título, descripción, condición, plataforma
  • Botón para guardar el juego en la biblioteca

API Client

Funciones disponibles en src/lib/api.ts:

// Buscar juegos
metadataApi.searchGames(params: SearchGamesParams): Promise<EnrichedGame[]>

// Crear juego desde metadatos
metadataApi.createGameFromMetadata(data: CreateGameFromMetadataInput): Promise<Game>

Flujo de Usuario

  1. El usuario navega a /games/add
  2. Ingresa un título de búsqueda (opcionalmente plataforma y año)
  3. Hace clic en "Buscar"
  4. El frontend llama a metadataApi.searchGames()
  5. El backend busca en IGDB, RAWG y TheGamesDB
  6. Los resultados se muestran en SearchResults
  7. El usuario selecciona un resultado
  8. Se abre GamePreviewDialog con los metadatos
  9. El usuario puede editar los campos según sea necesario
  10. Hace clic en "Guardar"
  11. El frontend llama a metadataApi.createGameFromMetadata()
  12. El juego se crea en la base de datos
  13. El usuario es redirigido a la página del juego

Configuración

Variables de Entorno

Backend:

# IGDB
IGDB_CLIENT_ID=your_client_id
IGDB_CLIENT_SECRET=your_client_secret

# RAWG
RAWG_API_KEY=your_api_key

# TheGamesDB
THEGAMESDB_API_KEY=your_api_key

Frontend:

NEXT_PUBLIC_API_URL=http://localhost:3003/api

Tests

Backend Tests

  • tests/services/metadataService.spec.ts: Tests del servicio de búsqueda
  • tests/routes/metadata.spec.ts: Tests de endpoints de metadatos
  • tests/routes/games.spec.ts: Tests de endpoints de juegos

Ejecutar tests:

cd backend
yarn test

Frontend Tests

  • src/components/games/__tests__/SearchForm.spec.ts: Tests del formulario de búsqueda
  • src/components/games/__tests__/SearchResults.spec.ts: Tests de resultados de búsqueda
  • src/components/games/__tests__/GamePreviewDialog.spec.ts: Tests del diálogo de previsualización

Ejecutar tests:

cd frontend
yarn test

Consideraciones de Diseño

Múltiples Fuentes

El sistema busca en múltiples fuentes simultáneamente para maximizar la probabilidad de encontrar resultados. Cada resultado incluye:

  • La fuente de los datos (source)
  • Los IDs externos (externalIds) para referencia futura

Normalización de Datos

Los datos de diferentes fuentes se normalizan a un formato común (EnrichedGame):

  • name y title se unifican
  • Las fechas se normalizan a formato ISO
  • Los géneros se mapean a strings
  • Las plataformas se normalizan

Validación

  • Los parámetros de búsqueda se validan con Zod
  • Los datos de creación de juego se validan antes de persistir
  • Los campos opcionales tienen valores por defecto apropiados

Error Handling

  • Errores de API externas no bloquean la búsqueda en otras fuentes
  • Errores de validación se devuelven con mensajes claros
  • Errores de red se manejan con reintentos y timeouts

Rendimiento

  • Las búsquedas en múltiples fuentes se ejecutan en paralelo
  • Los resultados se cachean por un período corto
  • Las imágenes se cargan de forma diferida (lazy loading)

Seguridad

  • Las claves de API se almacenan en variables de entorno
  • No se exponen credenciales en el frontend
  • Los inputs se validan y sanitizan
  • Se implementan rate limiting en las APIs externas

Roadmap Futuro

  • Soporte para más fuentes de metadatos
  • Búsqueda avanzada con filtros adicionales
  • Sugerencias de búsqueda mientras se escribe
  • Importación masiva desde listas externas
  • Sincronización automática de metadatos