# Modelo de datos — Entidades y esquema sugerido

## Diagrama ER (texto)

Game ↔ RomFile (1‑N)
Game ↔ Artwork (1‑N)
Game ↔ Platform (N‑N)
Game ↔ Tag (N‑N)
Game ↔ Purchase (1‑N)
Game ↔ PriceHistory (1‑N)

---

## Entidades principales (campos sugeridos)

### Game

- `id` (cuid) — identificador.
- `title` (string) — nombre principal.
- `slug` (string) — único, legible.
- `description` (text) — opcional.
- `releaseDate` (DateTime?) — fecha principal.
- `igdbId`, `rawgId`, `thegamesdbId` (Int?) — ids externos.
- `extra` (String?) — JSON serializado (compatible con SQLite); usar `JSON.parse`/`JSON.stringify` al leer/escribir.
- `createdAt`, `updatedAt`.

### Platform

- `id`, `name`, `slug`, `generation`.

### RomFile

- `id`, `path`, `filename`, `checksum` (unique), `size` (int), `format`, `hashes` (String? — JSON serializado, ej.: {"crc32":"...","md5":"..."}), `status` (active/missing), `addedAt`, `lastSeenAt`, `gameId`.

### Artwork

- `id`, `gameId`, `type` (cover/screenshot), `sourceUrl`, `localPath`, `width`, `height`, `fetchedAt`.

### Purchase

- `id`, `gameId`, `priceCents` (int), `currency`, `store`, `date`, `receiptPath`.

### PriceHistory

- `id`, `gameId`, `priceCents`, `currency`, `recordedAt`, `source`.

### Tag

- `id`, `name` (unique), color.

### User (opcional)

- `id`, `name`, `email` (unique), `passwordHash`, `role`.

---

## Índices y constraints recomendados

- `RomFile.checksum` — **UNIQUE** (detectar duplicados).
- `Game`: índice por `title` y `slug` (`slug` único).
- Composite unique sugerido: `[primaryPlatformId, title, releaseDate]` para evitar duplicados de una misma versión/plataforma.
- Índices para búsquedas frecuentes (title, platform, tags).

---

## Fragmento `schema.prisma` (ejemplo)

```prisma
datasource db {
  provider = "sqlite" // usar SQLite para desarrollo; cambiar a postgresql en producción si se necesita JSON nativo
  url      = env("DATABASE_URL")
}

generator client {
  provider = "prisma-client-js"
}

model Game {
  id             String    @id @default(cuid())
  title          String
  slug           String    @unique
  description    String?
  releaseDate    DateTime?
  igdbId         Int?      @unique
  rawgId         Int?      @unique
  thegamesdbId   Int?      @unique
  platforms      Platform[]
  romFiles       RomFile[]
  artworks       Artwork[]
  tags           Tag[]
  extra          String?   // JSON serializado (usar JSON.parse/JSON.stringify para leer y escribir)
  createdAt      DateTime  @default(now())
  updatedAt      DateTime  @updatedAt
  @@index([title])
  @@unique([slug])
}

model Platform {
  id    String @id @default(cuid())
  name  String @unique
  slug  String @unique
  games Game[]
}

model RomFile {
  id         String   @id @default(cuid())
  path       String
  filename   String
  checksum   String   @unique
  size       Int
  format     String
  hashes     String?  // JSON serializado (ej.: {"crc32":"...","md5":"..."})
  game       Game?    @relation(fields: [gameId], references: [id])
  gameId     String?
  addedAt    DateTime @default(now())
  lastSeenAt DateTime?
  status     String   @default("active")
  @@index([checksum])
}

model Artwork {
  id        String   @id @default(cuid())
  game      Game     @relation(fields: [gameId], references: [id])
  gameId    String
  type      String
  sourceUrl String
  localPath String?
  width     Int?
  height    Int?
  fetchedAt DateTime @default(now())
}

model Purchase {
  id         String   @id @default(cuid())
  game       Game     @relation(fields: [gameId], references: [id])
  gameId     String
  priceCents Int
  currency   String
  store      String?
  date       DateTime
  receiptPath String?
}

model PriceHistory {
  id         String   @id @default(cuid())
  game       Game     @relation(fields: [gameId], references: [id])
  gameId     String
  priceCents Int
  currency   String
  recordedAt DateTime @default(now())
  source     String?
}

model Tag {
  id    String @id @default(cuid())
  name  String @unique
  games Game[]
}
```

> Nota: para monedas se recomienda almacenar `priceCents` (int) para compatibilidad; si se usa Postgres se puede optar por `Decimal`. Nota: SQLite no soporta tipos JSON nativos; en este ejemplo se usan `String` para JSON serializado. Si migras a Postgres, puedes usar `Json`/`JsonB` para campos flexibles.

---

## Migraciones y evolución del esquema

- Usar **Prisma Migrate** para versionar cambios.
- Preferir migraciones no destructivas (añadir columnas `NULL` y rellenarlas en background).
- Mantener seeds de desarrollo para pruebas manuales y reproducibles.

---

## Fuentes

- Prisma schema conventions, patterns para modelado relacional y técnicas de deduplicación de archivos.

---

**Metadatos**
Autor: Quasar (investigación automatizada)
Última actualización: 2026-02-07
