Ir al contenido

Backend

Documentación del proyecto api/: contratos, endpoints, autenticación y el esquema de permisos por rol.

  • Referencia de API — endpoints, request/response, códigos de error. Un endpoint sin documentar no está terminado.

  • Autenticación — cómo se emite y renueva el token, cómo se cierra sesión.

  • Autorización — cómo se implementa el modelo de permisos.

  • Errores — catálogo de códigos y qué significa cada uno para el cliente.

Al 21-sep-2026:

  • M0 — Auth + RBAC: ✅ (20-ago-2026)
  • M1 — Productos: ✅ (22-ago-2026)
  • M2 — Stock: ✅ (22-ago-2026)
  • M3 — Insumos, M4 — Producción, M5 — Clientes, M6 — Ventas, M7 — Retornables: ✅
  • M9 — Proveedores, M11 — Contador, M12 — Alertas: ✅
  • M13 — Auditoría: ✅ (transversal desde M0)
  • M14 — Clientes ubicables: ✅ (10-sep-2026)
  • M15 — Seguimientos: ✅ (21-sep-2026)
  • M10 — Precios: ✅ absorbido por M1 y M6
  • M8 — Rutas y seller mobile: ⏸ POST-MVP (diferido)

1091 tests en api/, verificados de punta a punta contra web/ y la base. Bruno corriendo en CI contra un servidor real.

Repositorio: aquazaku-api.

Endpoint Quién puede Notas
GET /health cualquiera Señal de vida
POST /api/auth/sign-in/email cualquiera Better-Auth. Límite: 5 intentos / 15 min
POST /api/auth/request-password-reset cualquiera Límite: 3 / 15 min
POST /api/auth/reset-password con token Cierra todas las sesiones
GET /auth/me con sesión Perfil + roles + permisos resueltos
POST /auth/sign-out con sesión
POST /auth/change-password con sesión Exige la contraseña actual
GET /users, GET /users/:id usuarios:ver Incluye los roles
POST /users usuarios:crear
PATCH /users/:id usuarios:editar Desactivar cierra sus sesiones
PUT /users/:id/roles usuarios:editar Idempotente; hace efecto en el acto
GET /audit auditoria:ver Filtros + paginación por cursor
GET /productos productos:ver ?estado=activos|inactivos|todos, por defecto activos
GET /productos/:id productos:ver
POST /productos productos:crear El código lo genera el sistema (RN-CAT-11)
PATCH /productos/:id productos:editar Solo el nombre — no toca precios
PATCH /productos/:id/precios productos:editar_precios Los tres juntos. Audita antes y después
POST /productos/:id/desactivar productos:desactivar
POST /productos/:id/reactivar productos:desactivar
GET /stock stock:ver Por producto: total, vendible y vencido
GET /stock/:productoId/lotes stock:ver Con saldo, del más próximo a vencer
GET /stock/movimientos stock:ver El libro. Filtros + paginación por cursor
POST /stock/entradas stock:ajustar Crea el lote. Motivo obligatorio
POST /stock/ajustes stock:ajustar ± sobre un lote. Motivo obligatorio
POST /stock/descartes stock:descartar Causa obligatoria (RN-STK-06)

Todos menos los tres primeros pasan por requireAuth y requirePermission.

  • modules/authz/ — matriz de permisos ejecutable, alcances, can(), scopedCondition(), middleware y emisión de auditoría. La matriz es una transcripción 1-a-1 de Roles y permisos, y un test la verifica celda por celda contra una lista derivada del documento.
  • modules/auth/ — Better-Auth sobre el schema propio, transportes de correo (Resend y Mailpit) y límite de intentos.
  • modules/users/ — ABM con la protección del último administrador.
  • modules/audit/ — consulta de la bitácora.
Código Status Cuándo
UNAUTHENTICATED 401 No vino cookie de sesión
SESSION_EXPIRED 401 Vino una que el servidor ya no acepta
USER_INACTIVE 401 La cuenta fue desactivada (RN-ACC-05)
FORBIDDEN 403 Autenticado, sin permiso. Queda auditado
AUDIT_UNAVAILABLE 500 No se pudo auditar una acción sensible, así que no se ejecutó — ADR-0007
RATE_LIMITED 429 Trae retry-after y reintentarEn
VALIDATION_ERROR 400 Con detalle por campo
ULTIMO_ADMIN 409 Dejaría el sistema sin administrador (RN-ACC-06)
EMAIL_EN_USO 409 El email ya existe (citext: choca sin importar el case)
PRODUCTO_NO_ENCONTRADO 404
PRECIO_MINIMO_INVALIDO 422 El piso superaría un precio de lista (RN-CAT-04)
PRODUCTO_YA_INACTIVO 409 Desactivar uno que ya lo estaba
PRODUCTO_YA_ACTIVO 409 Reactivar uno que ya lo estaba
PRODUCTO_CON_STOCK 409 Desactivar uno con unidades en stock (RN-CAT-02)
STOCK_INSUFICIENTE 409 Se pidió más de lo disponible. Trae el saldo real
LOTE_NO_ENCONTRADO 404
MOTIVO_REQUERIDO 422 Ajuste sin motivo (RN-STK-02)
CANTIDAD_INVALIDA 422 Cero, negativa donde no corresponde, o no entera

Hay una colección de Bruno versionada en el repo: Explorar la API con Bruno.

  • ADR-0004 — audit_log inmutable con dos capas independientes.
  • ADR-0005 — los alcances fallan cerrados.
  • RN-ACC-06 y RN-ACC-07 — dos reglas de negocio que aparecieron construyendo.
  • Spec de M0 — el plan tiene además notas de ejecución task por task, con lo que hubo que corregir.
  • ADR-0001 — stack.
  • ADR-0003 — matriz y multi-rol.