Skip to main content
Los endpoints en src/app/api/**/route.ts siguen un patrón consistente, en este orden:

1. requireAdmin() en todo /api/admin/*

Todo endpoint bajo /api/admin/* empieza llamando a requireAdmin() de @/lib/require-admin:
requireAdmin() devuelve { error, session }. Si error no es null, el handler lo retorna tal cual — ya es un 401 (sin sesión) o un 403 (sesión sin rol ADMIN).

2. Validación con Zod safeParse

Los searchParams o el body se validan con safeParse. Si falla, la respuesta es 400 con esta forma:
issues es la salida de parsed.error.flatten().

3. Listados paginados por cursor

Los listados paginan con take: limit + 1 y, si hay cursor, con cursor: { id: cursor } más skip: 1. La fila extra sirve para saber si hay otra página sin hacer un segundo count. La respuesta tiene siempre nextCursor y hasMore; el nombre de la clave con el array cambia según el recurso (users, camellos…):
El cursor es el id de la última fila de la página anterior — también en el listado de usuarios, donde antes era un cursor compuesto codificado en base64url. Ese cursor especial se retiró cuando el listado de usuarios pasó a poder ordenarse por columna: con orderBy variable, un id simple es suficiente y funciona igual que en camellos.

4. try/catch envolviendo todo

Todo el handler queda envuelto en try/catch. El catch registra el error con un prefijo que identifica el endpoint y responde 500:

Idioma de los mensajes

Los mensajes de error de la API van en español sin tildes"Parametros invalidos", "No autenticado", "Sin permisos de administrador" — porque son valores literales que el cliente puede llegar a comparar. La UI que los muestra sí usa tildes.