Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/akibanks/api-tienda-vinilos/llms.txt

Use this file to discover all available pages before exploring further.

VinylVibes uses PostgreSQL (hosted on Neon) managed through Prisma ORM. The schema defines five models that together cover every core concern of the application: user accounts and authentication, purchase orders, individual order line items, shipping addresses, and per-user browsing history.

Models overview

usuario

User accounts. Stores credentials, the assigned role, and timestamps. Every other entity in the schema traces back to a usuario record.

venta

Purchase orders. Records the order total, lifecycle status, and a foreign key to the purchasing usuario.

linea_venta

Individual records (line items) inside an order. Each row stores the Discogs release ID, title, artist, unit price, and quantity.

envio

Shipping address attached to an order. One-to-one with venta; cascade-deleted when the parent order is removed.

historial_usuario

The last 10 Discogs releases viewed by a user. Maintained as a FIFO ring in application logic — the oldest entry is evicted when an 11th item arrives.

Schema details

usuario

model usuario {
  id_usuario Int                 @id @default(autoincrement())
  nombre     String              @unique @db.VarChar(100)
  correo     String              @unique @db.VarChar(150)
  contrasena String              @db.VarChar(255)
  rol        rol_usuario         @default(cliente)
  created_at DateTime            @default(now())
  updated_at DateTime            @default(now())
  ventas     venta[]
  historial  historial_usuario[]
}
FieldTypeNullableDefaultDescription
id_usuarioIntNoauto-incrementPrimary key
nombreString (VARCHAR 100)NoUnique username used for login
correoString (VARCHAR 150)NoUnique email; auto-generated as <nombre>@vinylvibes.local on registration
contrasenaString (VARCHAR 255)Nobcrypt hash of the user’s password
rolrol_usuarioNoclienteEnum controlling access level
created_atDateTimeNonow()Account creation timestamp
updated_atDateTimeNonow()Last update timestamp (not auto-updated by Prisma; updated by application code)

venta

model venta {
  id_venta   Int          @id @default(autoincrement())
  id_cliente Int
  total      Decimal      @default(0) @db.Decimal(12, 2)
  estado     estado_venta @default(pendiente)
  fecha      DateTime     @default(now())
  updated_at DateTime     @default(now())
  cliente    usuario      @relation(fields: [id_cliente], references: [id_usuario])
  lineas     linea_venta[]
  envio      envio?
}
FieldTypeNullableDefaultDescription
id_ventaIntNoauto-incrementPrimary key
id_clienteIntNoFK → usuario.id_usuario
totalDecimal(12,2)No0Order total in the store’s currency
estadoestado_ventaNopendienteOrder lifecycle state; see enum below
fechaDateTimeNonow()Order creation timestamp
updated_atDateTimeNonow()Last modification timestamp
In the current checkout flow, new orders are created with estado = 'pagada' directly — pendiente is the schema default but is not used by the checkout endpoint.

linea_venta

model linea_venta {
  id_linea   Int     @id @default(autoincrement())
  id_venta   Int
  discogs_id String  @db.VarChar(20)
  titulo     String  @db.VarChar(200)
  artista    String  @db.VarChar(200)
  cantidad   Int
  p_unitario Decimal @db.Decimal(10, 2)
  subtotal   Decimal @db.Decimal(10, 2)
  venta      venta   @relation(fields: [id_venta], references: [id_venta], onDelete: Cascade)

  @@unique([id_venta, discogs_id])
}
FieldTypeNullableDefaultDescription
id_lineaIntNoauto-incrementPrimary key
id_ventaIntNoFK → venta.id_venta (cascade delete)
discogs_idString (VARCHAR 20)NoDiscogs release ID
tituloString (VARCHAR 200)NoAlbum title at the time of purchase
artistaString (VARCHAR 200)NoArtist name at the time of purchase
cantidadIntNoNumber of copies ordered
p_unitarioDecimal(10,2)NoBackend-calculated unit price
subtotalDecimal(10,2)Nop_unitario × cantidad
titulo and artista are denormalised onto the line item intentionally. Because prices and metadata come from the live Discogs API, snapshotting them at checkout time preserves an accurate record of what the customer was charged.

envio

model envio {
  id_envio        Int      @id @default(autoincrement())
  id_venta        Int      @unique
  nombre_receptor String   @db.VarChar(120)
  calle           String   @db.VarChar(200)
  numero_ext      String   @db.VarChar(20)
  numero_int      String?  @db.VarChar(20)
  colonia         String   @db.VarChar(100)
  ciudad          String   @db.VarChar(100)
  estado          String   @db.VarChar(100)
  codigo_postal   String   @db.VarChar(10)
  referencias     String?
  created_at      DateTime @default(now())
  venta           venta    @relation(fields: [id_venta], references: [id_venta], onDelete: Cascade)
}
FieldTypeNullableDefaultDescription
id_envioIntNoauto-incrementPrimary key
id_ventaIntNo (unique)FK → venta.id_venta (cascade delete, one-to-one)
nombre_receptorString (VARCHAR 120)NoFull name of the recipient
calleString (VARCHAR 200)NoStreet name
numero_extString (VARCHAR 20)NoExterior number
numero_intString (VARCHAR 20)YesnullInterior/apartment number (optional)
coloniaString (VARCHAR 100)NoNeighbourhood / colonia
ciudadString (VARCHAR 100)NoCity
estadoString (VARCHAR 100)NoState or province
codigo_postalString (VARCHAR 10)NoPostal code
referenciasString (text)YesnullAdditional delivery notes (optional)
created_atDateTimeNonow()Record creation timestamp

historial_usuario

model historial_usuario {
  id_historial Int      @id @default(autoincrement())
  id_usuario   Int
  discogs_id   String   @db.VarChar(20)
  titulo       String   @db.VarChar(200)
  artista      String   @db.VarChar(200)
  genero       String?  @db.VarChar(80)
  estilo       String?  @db.VarChar(80)
  visto_en     DateTime @default(now())
  usuario      usuario  @relation(fields: [id_usuario], references: [id_usuario], onDelete: Cascade)

  @@index([id_usuario])
  @@index([discogs_id])
  @@index([visto_en(sort: Desc)])
}
FieldTypeNullableDefaultDescription
id_historialIntNoauto-incrementPrimary key
id_usuarioIntNoFK → usuario.id_usuario (cascade delete)
discogs_idString (VARCHAR 20)NoDiscogs release ID that was viewed
tituloString (VARCHAR 200)NoAlbum title at the time of viewing
artistaString (VARCHAR 200)NoArtist name at the time of viewing
generoString (VARCHAR 80)YesnullPrimary Discogs genre (if available)
estiloString (VARCHAR 80)YesnullPrimary Discogs style (if available)
visto_enDateTimeNonow()When the record was last viewed; updated on re-visit

Enums

estado_venta

enum estado_venta {
  pendiente
  pagada
  enviada
  entregada
  cancelada
}
ValueDescription
pendienteOrder created but payment not yet confirmed. This is the schema default, though the current checkout flow skips straight to pagada.
pagadaPayment confirmed. This is the state applied by POST /checkout.
enviadaOrder has been dispatched by the seller.
entregadaOrder received and delivered to the customer.
canceladaOrder cancelled, regardless of prior state.
Only admin accounts (not demo) can transition an order’s estado via PUT /admin/ventas/:id/estado. All five values in the enum are valid targets for that endpoint.

rol_usuario

enum rol_usuario {
  cliente
  vendedor
  admin
  demo
}
ValueDescription
clienteDefault role assigned on registration. Grants access to catalog browsing, history tracking, checkout, and personal purchase history.
vendedorReserved for future inventory management features. Currently has the same permissions as cliente.
adminFull access — all user-facing endpoints plus all admin endpoints, including user management, sales management, and Redis diagnostics.
demoRead-only admin. Can access GET admin endpoints and GET /redis-ping, but is blocked from all write operations with a 403.
The demo role cannot be assigned through the API. PUT /admin/usuarios/:id/rol only accepts cliente, vendedor, and admin as valid values. Granting demo requires a direct database update.

Relationships

usuario ──< venta              (one-to-many)
usuario ──< historial_usuario  (one-to-many)
venta   ──< linea_venta        (one-to-many, cascade delete)
venta   ──  envio              (one-to-one optional, cascade delete)
ParentChildCardinalityOn Delete
usuarioventaOne-to-manyNo cascade (orphan orders are kept)
usuariohistorial_usuarioOne-to-manyCascade — history deleted with user
ventalinea_ventaOne-to-manyCascade — line items deleted with order
ventaenvioOne-to-one (optional)Cascade — shipping address deleted with order
  • usuario → venta — A single user can have many orders. Deleting a user does not cascade-delete their orders; existing venta rows continue to hold the id_cliente FK.
  • venta → linea_venta — Each order has one or more line items. onDelete: Cascade ensures no orphaned line items remain if an order is removed.
  • venta → envio — The relation is optional (envio?) on the venta side and enforced as unique on envio.id_venta, making it a true one-to-one. Cascade delete keeps referential integrity.
  • usuario → historial_usuario — Cascade delete removes all browsing history when the parent user account is deleted.

Indexes

Three indexes are declared on historial_usuario:
IndexField(s)Purpose
@@index([id_usuario])id_usuarioFast lookup of all history rows for a given user — the primary query pattern for GET /historial and recommendation boosting
@@index([discogs_id])discogs_idFast lookup to check whether a given release already exists in a user’s history before deciding to insert or update
@@index([visto_en(sort: Desc)])visto_en DESCEfficient retrieval of the most-recently-viewed entries and identification of the oldest entry during the FIFO eviction step
One composite unique constraint is declared on linea_venta:
ConstraintFieldsPurpose
@@unique([id_venta, discogs_id])id_venta, discogs_idPrevents the same Discogs release from appearing twice in a single order

Browsing history cap

The 10-item limit is enforced in application logic inside POST /historial, not through a database constraint. The database itself imposes no maximum row count per user.
The historial_usuario table is managed as a fixed-size FIFO queue per user. The logic runs on every POST /historial call:
  1. Upsert check — If the incoming discogs_id already exists in the user’s history, only visto_en (and optionally genero/estilo) is updated. The total count is unchanged, and the FIFO eviction step is skipped.
  2. Count check — If the release is new to this user’s history, the application counts existing rows: prisma.historial_usuario.count({ where: { id_usuario } }).
  3. Eviction — If the count is 10 or more, the row with the earliest visto_en value is fetched and deleted before the new row is inserted. This keeps the table at a maximum of 10 unique releases per user at all times.
  4. Insert — The new history entry is created.
POST /historial (new discogs_id)


  count rows for user

   count < 10?──── Yes ────► insert new row

        No


  find oldest visto_en row


  delete oldest row


  insert new row

Build docs developers (and LLMs) love