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 API uses a simple role-based access control system stored in the usuario.rol column. Every JWT token issued by POST /login encodes the user’s current role alongside their ID and username. On protected endpoints, middleware decodes the token and inspects the role before allowing the request to proceed.

Role definitions

cliente

Default on registration. Can browse the catalog, record browsing history, place orders via checkout, and view their own purchase history. Cannot access any admin endpoint.

vendedor

Future use. Currently has the same access level as cliente. This role is reserved for planned inventory-management features and has no additional permissions at present.

admin

Full access. Everything a cliente can do, plus all admin endpoints: user listing and deletion, role assignment, sales listing and status management, and Redis diagnostics.

demo

Read-only admin. May access GET admin endpoints and the Redis diagnostic endpoint, but is blocked from all write or mutating operations with a 403 Solo lectura response.

Full capability matrix

Capabilityclientevendedoradmindemo
Browse catalog (search, recent, genre)
View record detail, history, video
Record browsing history (POST /historial)
View own browsing history (GET /historial)
Place an order (POST /checkout)
View own purchases (GET /mis-compras)
List all users (GET /admin/usuarios)
List all sales (GET /admin/ventas)
View sale detail (GET /admin/ventas/:id)
Redis diagnostic (GET /redis-ping)
Change a user’s role (PUT /admin/usuarios/:id/rol)
Delete a user (DELETE /admin/usuarios/:id)
Change order status (PUT /admin/ventas/:id/estado)

How roles are set

On registration

New accounts always receive the cliente role. This is hardcoded in the POST /registro handler — the request body has no role field, and the value is never derived from client input:
await prisma.usuario.create({
  data: {
    nombre:     nombre_usuario.trim(),
    correo:     correoPlaceholder,
    contrasena: hash,
    rol:        'cliente',   // always hardcoded
  },
});
There is no self-promotion path. A user cannot elevate their own role through any API call.

Changing a role (admin only)

An admin account can update any other user’s role via:
PUT /admin/usuarios/:id/rol
Authorization: Bearer <admin-token>

{ "rol": "vendedor" }
The endpoint validates the supplied value against an explicit allowlist:
if (!['cliente', 'vendedor', 'admin'].includes(rol))
  return res.status(400).json({ error: 'Rol inválido.' });
The demo role is not in the allowlist and cannot be set through the API. Assigning demo to a user requires a direct database update (e.g. via psql or the Neon dashboard). This is by design — demo is a special operational role, not a normal user tier.

Middleware

Three middleware functions in index.js implement the access control layer. They are composed as Express middleware chains on each route.

verificarToken

Validates the Authorization header and attaches the decoded payload to req.usuario.
function verificarToken(req, res, next) {
  const auth = req.headers.authorization;
  if (!auth?.startsWith('Bearer '))
    return res.status(401).json({ error: 'Token de autenticación requerido.' });
  try {
    req.usuario = jwt.verify(auth.slice(7), JWT_SECRET);
    next();
  } catch {
    res.status(401).json({ error: 'Token inválido o expirado. Vuelve a iniciar sesión.' });
  }
}
  • Expects the header in the exact format Authorization: Bearer <token>.
  • On success, sets req.usuario to the decoded JWT payload: { id, nombre, rol }.
  • Returns 401 if the header is missing, malformed, or if the token is invalid or expired.
  • JWT tokens expire after 7 days (JWT_EXPIRY = '7d').

soloAdmin

Gates a route to users with the admin or demo role. Must be used after verificarToken.
function soloAdmin(req, res, next) {
  if (req.usuario?.rol !== 'admin' && req.usuario?.rol !== 'demo') {
    return res.status(403).json({ error: 'Acceso denegado: se requieren permisos de administrador.' });
  }
  next();
}
  • Allows: admin, demo.
  • Rejects: cliente, vendedor403.
  • Used on all admin read endpoints: GET /admin/usuarios, GET /admin/ventas, GET /admin/ventas/:id, GET /redis-ping.

soloAdminEscritura

Blocks the demo role from executing write operations. Must be used after both verificarToken and soloAdmin.
function soloAdminEscritura(req, res, next) {
  if (req.usuario?.rol === 'demo')
    return res.status(403).json({ error: 'Tu cuenta es de solo lectura. No puedes realizar esta acción.' });
  next();
}
  • Allows: admin.
  • Rejects: demo403 with the message "Tu cuenta es de solo lectura. No puedes realizar esta acción.".
  • Used on all admin write endpoints: PUT /admin/usuarios/:id/rol, DELETE /admin/usuarios/:id, PUT /admin/ventas/:id/estado.

Middleware composition example

// Read — admin AND demo allowed
app.get('/admin/ventas', verificarToken, soloAdmin, handler);

// Write — admin only (demo rejected by soloAdminEscritura)
app.put('/admin/ventas/:id/estado', verificarToken, soloAdmin, soloAdminEscritura, handler);
Because soloAdminEscritura only checks for demo, it always runs after soloAdmin. By the time soloAdminEscritura is invoked, any non-admin, non-demo role has already been rejected by soloAdmin.

Endpoint access matrix

The table below maps every endpoint group to the minimum role required.
EndpointMethodAuth requiredRoles allowed
/registroPOSTNonePublic
/loginPOSTNonePublic
/buscarGETNonePublic
/recientesGETNonePublic
/genero/:generoGETNonePublic
/disco/:idGETNonePublic
/disco/:id/historiaGETNonePublic
/disco/:id/videoGETNonePublic
/disco/:id/recomendacionesGETOptionalPublic (personalised if token provided)
/historialPOSTJWTcliente, vendedor, admin, demo
/historialGETJWTcliente, vendedor, admin, demo
/checkoutPOSTJWTcliente, vendedor, admin, demo
/mis-comprasGETJWTcliente, vendedor, admin, demo
/admin/usuariosGETJWTadmin, demo
/admin/ventasGETJWTadmin, demo
/admin/ventas/:idGETJWTadmin, demo
/redis-pingGETJWTadmin, demo
/admin/usuarios/:id/rolPUTJWTadmin only
/admin/usuarios/:idDELETEJWTadmin only
/admin/ventas/:id/estadoPUTJWTadmin only
GET /disco/:id/recomendaciones accepts a Bearer token but does not require one. When a valid token is present, the endpoint personalises results by boosting genres that appear in the user’s browsing history. Anonymous requests receive non-personalised recommendations instead.

Error responses by role violation

ScenarioHTTP statusError message
No Authorization header on a protected route401"Token de autenticación requerido."
Token present but invalid or expired401"Token inválido o expirado. Vuelve a iniciar sesión."
cliente or vendedor hitting an admin route403"Acceso denegado: se requieren permisos de administrador."
demo role hitting a write admin route403"Tu cuenta es de solo lectura. No puedes realizar esta acción."
PUT /admin/usuarios/:id/rol with an invalid role value400"Rol inválido."

Build docs developers (and LLMs) love