Files
quasar/plans/gestor-coleccion-plan-phase-4.md
Benito Rodríguez 4298b003d9 feat: import job runner in-memory
- Añade ImportRunner en memoria con concurrencia configurable
- Tests TDD para enqueue, concurrencia y comportamiento tras stop
- Actualiza /api/import/scan para encolar jobs y registrar errores
- Ajusta tsconfig.json para incluir tests en comprobaciones de tipo
2026-02-08 22:24:56 +01:00

132 lines
8.9 KiB
Markdown

## Plan: Importador de ROMs (Fase 4)
TL;DR: Estabilizar el entorno de tests y, mediante TDD, implementar la pipeline de importación de ROMs: escaneo de ficheros, cálculo de checksums, verificación contra DATs, persistencia en Prisma y un runner en background. Se comenzará con un runner en memoria y se dejará la puerta abierta para migrar a Redis posteriormente.
**Phases**
1. **Phase 1: Estabilizar entorno y ejecutar tests**
- **Objective:** Obtener una línea base reproducible donde `yarn --cwd backend test` se ejecute y muestre resultados claros.
- **Files/Functions to Modify/Create:** `backend/tsconfig.json`, `backend/package.json`, `backend/prisma/schema.prisma`, `backend/src/plugins/prisma.ts`.
- **Tests to Write:** Ninguno nuevo; ejecutar y capturar los tests existentes (`backend/tests/**`).
- **Steps:**
1. Ejecutar `yarn install` en la raíz y generar el cliente Prisma (`prisma generate`) en `backend/`.
2. Ejecutar `yarn --cwd backend test` y documentar fallos.
3. Corregir problemas de `prisma generate` o `tsconfig` y validar que los tests relevantes pasan.
2. **Phase 2: Persistencia básica e integración con la ruta de import**
- **Objective:** Implementar `importService` que use `scanDirectory` y `computeHashes` para persistir `RomFile` (upsert por checksum) y, cuando sea posible, vincular/crear `Game`.
- **Files/Functions to Modify/Create:** `backend/src/services/importService.ts`, actualizar `backend/src/routes/import.ts` para invocar el servicio.
- **Tests to Write:** `backend/tests/services/importService.spec.ts`, actualizar `backend/tests/routes/import.spec.ts` para escenarios `persist: true/false`.
- **Steps:**
1. Escribir tests (falla roja).
2. Implementar mínimo para pasar tests (green).
3. Refactor y asegurar idempotencia (re-run tests).
3. **Phase 3: ArchiveReader — soportar zip/7z/chd**
- **Objective:** Leer/listar contenido de contenedores (ZIP, 7z, CHD) sin extracción completa para indexar ROMs internos.
- **Files/Functions to Modify/Create:** `backend/src/services/archiveReader.ts`; adaptar `backend/src/services/fsScanner.ts` para delegar en `archiveReader` cuando `isArchive`.
- **Tests to Write:** `backend/tests/services/archiveReader.spec.ts` (fixtures: zips/7z/CHD bajo `backend/tests/fixtures`).
- **Steps:**
1. Añadir tests que describan el comportamiento esperado (falla roja).
2. Implementar con librería elegida y validar en CI con binarios instalados.
4. **Phase 4: DAT parsing y verificación**
- **Objective:** Parsear DAT XML y comprobar si un ROM coincide con una entrada DAT (por checksums/size/name).
- **Files/Functions to Modify/Create:** `backend/src/services/datVerifier.ts` (completar), añadir utilidades de parseo XML.
- **Tests to Write:** `backend/tests/services/datVerifier.spec.ts` (unidad + integración, usar `INTEGRATION=1` para pruebas que dependan de binarios/fixtures grandes).
- **Steps:**
1. Implementar parseo y matching (falla roja).
2. Integrarlo en `importService` para sugerir o asociar `Game`.
5. **Phase 5: Job runner en memoria (inicio) — migrable a Redis**
- **Objective:** Implementar un runner en memoria que procese jobs de import con control de concurrencia (`IMPORT_CONCURRENCY`), estado básico y capacidad de encolar tareas desde la ruta `/api/import/scan`.
- **Files/Functions to Modify/Create:** `backend/src/config.ts`, `backend/src/jobs/importRunner.ts`, tests en `backend/tests/jobs/importRunner.spec.ts`, actualizar `backend/src/routes/import.ts` para encolar jobs.
- **Tests to Write:** `backend/tests/jobs/importRunner.spec.ts` (enqueue/resolución, concurrencia, getStatus).
- **Steps:**
1. Escribir tests (falla roja).
2. Implementar runner in-memory (green).
3. Integrar con la ruta de import y validar comportamiento en tests.
6. **Phase 6: CI e integración de binarios**
- **Objective:** Preparar workflows para ejecutar pruebas de integración que dependan de binarios (`7z`, `chdman`) y asegurar `prisma generate` en CI.
- **Files/Functions to Modify/Create:** `.github/workflows/ci.yml`, documentación en `README.md`.
- **Steps:**
1. Crear workflow que haga `yarn install`, `yarn --cwd backend prisma generate`, instale binarios (o use contenedor preparado) y ejecute `yarn --cwd backend test` con `INTEGRATION=1` cuando corresponda.
**Open Questions**
1. ¿Persistimos `ImportJob` en DB desde el inicio (útil para resume/retry) o lo dejamos para una futura migración a Redis? (Persistir ahora / Posponer)
2. ¿En CI preferís instalar `7z`/`chdman` o marcar tests de archive/CHD como opcionales con `INTEGRATION=1` y ejecutarlos solo si runner proporciona binarios? (Instalar / Opcional)
3. ¿Creación automática de `Game` al no encontrar DAT match? (Crear placeholder con `slug` / Solo guardar `RomFile`)
4. Política de colas a largo plazo: ¿Redis desde el inicio o in-memory ahora y migrar luego? (Usuario eligió: in-memory ahora)
## Plan: Importadores y gestión de ROMs (Fase 4)
Implementar servicios para escanear directorios de ROMs, detectar formatos (ZIP/7z/CHD), calcular checksums (CRC32/MD5/SHA1), verificar contra DATs (No-Intro/Redump) y persistir `RomFile` en la BD. El escaneo se lanzará desde el frontend, correrá como job en background y la ruta a las ROMs será una configuración del sistema (no se envía en cada request). Se añadirá la variable `IMPORT_CONCURRENCY` con cálculo por defecto.
**Phases 4**
1. **Phase 4.1: Tests y fixtures (TDD)**
- **Objective:** Escribir tests y fixtures que guiarán la implementación; los tests deben fallar inicialmente.
- **Files a crear:**
- `backend/tests/fixtures/simple-rom.bin` — fixture ROM sintética
- `backend/tests/fixtures/nested/nested-rom.bin` — fixture en subdirectorio
- `backend/tests/fixtures/dats/sample-no-intro.dat.xml` — DAT XML mínimo
- `backend/tests/services/fsScanner.spec.ts`
- `backend/tests/services/checksumService.spec.ts`
- `backend/tests/services/datVerifier.spec.ts` (marcar integración para binarios cuando aplique)
- `backend/tests/routes/import.spec.ts`
- **Criterio de aceptación:** Los tests existen y fallan por falta de implementación (TDD).
2. **Phase 4.2: Core — Scanner y checksums**
- **Objective:** Implementar `fsScanner` y `checksumService` con streaming y control de concurrencia.
- **Files a crear:**
- `backend/src/services/fsScanner.ts`
- `backend/src/services/checksumService.ts`
- `backend/src/lib/fileTypeDetector.ts`
- **Criterio de aceptación:** Tests unitarios de Phase 4.1 pasan para los casos no relacionados con archives/CHD.
3. **Phase 4.3: Archives y DAT verification**
- **Objective:** Implementar `archiveReader` (ZIP, 7z opcional) y `datVerifier`.
- **Files a crear:**
- `backend/src/services/archiveReader.ts`
- `backend/src/services/datVerifier.ts`
- **Notas:** CHD será soportado opcionalmente mediante `chdman` (si está instalado en el sistema); en la MVP se tratará CHD como blob para checksums si `chdman` no está presente.
4. **Phase 4.4: API, job en background y E2E**
- **Objective:** Añadir endpoint `POST /api/import/scan` (sin recibir path; usa la ruta preconfigurada), job runner en background, endpoints `GET /api/import/status/:taskId` y `GET /api/import/result/:taskId`, y pruebas E2E que verifiquen persistencia en Prisma.
- **Files a crear:**
- `backend/src/routes/import.ts`
- `backend/src/controllers/importController.ts`
- `backend/src/plugins/importJobs.ts` (cola en proceso; migrable a Redis/BullMQ)
- **Criterio de aceptación:** E2E de import completo pasa en CI (con binarios instalados según sea necesario).
**Decisiones tomadas**
- `chdman` soporte: opcional. Si está instalado, lo usaremos; si no, se calcula checksum y se trata como blob.
- Endpoint `POST /api/import/scan`: no recibe `path`; la ruta a las ROMs se configura en el sistema (env var `ROMS_PATH`).
- El job se ejecuta en background; el frontend lanza el job a petición del usuario (botón "Scan").
- Añadir `IMPORT_CONCURRENCY` (env var). Valor por defecto: `min(8, max(1, os.cpus().length - 1))` si no se configura.
- Tests que dependen de binarios (7z/chdman): se incluirán como tests de integración y se habilitarán en CI (instalación de binarios en workflow).
**Open Questions (resueltas por el usuario):**
1. Soporte `chdman` opcional — Aprobado.
2. No enviar `path` en payload; usar ruta preconfigurada — Aprobado (`ROMS_PATH`).
3. Job en background — Aprobado.
4. `IMPORT_CONCURRENCY` variable y fórmula por defecto — Aprobado.
5. Incluir tests dependientes de binarios y instalarlos en CI — Aprobado.
**Siguientes pasos (Phase 4.1 - TDD):**
1. Crear fixtures y tests unitarios marcados en Phase 4.1.
2. Ejecutar `yarn --cwd backend test` y observar tests fallidos.
3. Implementar servicios mínimos en Phase 4.2 para pasar tests básicos.
---
Metadatos:
- Autor: GitHub Copilot
- Fecha: 2026-02-08