Skip to content

Control de Acceso

Endpoints para gestionar el control de acceso físico al gimnasio usando dispositivos ControlID IdFace. El sistema permite enrolar usuarios (rostro + PIN/cédula) y validar el acceso en tiempo real según el tipo de membresía.

Admin / Staff Los endpoints de administración están restringidos a administradores y staff.

El sistema opera con 2 dispositivos en modo Online:

DispositivoNombrePolítica de Acceso
Talanquera (turnstile)Entrada principalMembresía ACTIVE (cualquier tipo)
Zona Premium (premium)Área exclusivaMembresía ACTIVE + tipo PREMIUM/VIP/ENTERPRISE

Los usuarios se enrolan en ambos dispositivos siempre. La validación de acceso ocurre en tiempo real cuando el usuario se identifica (rostro o PIN).

Registra un usuario en ambos dispositivos (crea usuario + asigna PIN con su cédula).

  • URL: /api/v1/access-control/enroll/:userProfileId
  • Método: POST
  • Autenticación Requerida: Sí (Admin/Staff)
  • userProfileId: ID del perfil de usuario a enrolar
{
"message": "Usuario enrolado exitosamente",
"data": {
"userProfileId": "clx1234567890",
"name": "Juan Pérez",
"controlIdUserId": 1234567890,
"enrolledDevices": ["turnstile", "premium"]
}
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].enroll[':userProfileId'].$post({
param: { userProfileId: 'clx1234567890' }
})

Inicia la captura facial en el dispositivo Talanquera vía remote_enroll. El usuario debe estar parado frente al dispositivo. Una vez capturada, la imagen se copia automáticamente al dispositivo Premium.

  • URL: /api/v1/access-control/enroll/:userProfileId/face
  • Método: POST
  • Autenticación Requerida: Sí (Admin/Staff)
  • userProfileId: ID del perfil de usuario
{
"message": "Rostro registrado exitosamente",
"data": {
"userProfileId": "clx1234567890",
"faceEnrolled": true,
"syncedTo": ["turnstile", "premium"]
}
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].enroll[':userProfileId'].face.$post({
param: { userProfileId: 'clx1234567890' }
})

Elimina un usuario de todos los dispositivos (usuario, PIN e imagen facial).

  • URL: /api/v1/access-control/enroll/:userProfileId
  • Método: DELETE
  • Autenticación Requerida: Sí (Admin/Staff)
  • userProfileId: ID del perfil de usuario
{
"message": "Usuario removido de los dispositivos",
"data": {
"removedFrom": ["turnstile", "premium"]
}
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].enroll[':userProfileId'].$delete({
param: { userProfileId: 'clx1234567890' }
})

Sincronización masiva: enrola todos los usuarios con cédula registrada en ambos dispositivos. Útil para setup inicial o después de un reset del dispositivo.

  • URL: /api/v1/access-control/sync
  • Método: POST
  • Autenticación Requerida: Sí (Admin)
{
"message": "Sincronización completada",
"data": {
"enrolled": 45,
"errors": 2
}
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].sync.$post()

Consulta si un dispositivo está online y obtiene información del sistema.

  • URL: /api/v1/access-control/devices/:deviceType/status
  • Método: GET
  • Autenticación Requerida: Sí (Admin/Staff)
  • deviceType: turnstile o premium
{
"data": {
"deviceType": "turnstile",
"online": true,
"info": {
"serial": "ABC123",
"firmware": "4.10.0",
"model": "iDFace"
}
}
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].devices[':deviceType'].status.$get({
param: { deviceType: 'turnstile' }
})

Obtiene los logs de acceso del dispositivo (eventos de entrada/salida).

  • URL: /api/v1/access-control/devices/:deviceType/logs
  • Método: GET
  • Autenticación Requerida: Sí (Admin/Staff)
  • deviceType: turnstile o premium
{
"data": [
{
"id": 1,
"time": 1698400000,
"event": 7,
"user_id": 1234567890,
"portal_id": 1
}
]
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].devices[':deviceType'].logs.$get({
param: { deviceType: 'turnstile' }
})

Lista todos los usuarios registrados en un dispositivo.

  • URL: /api/v1/access-control/devices/:deviceType/users
  • Método: GET
  • Autenticación Requerida: Sí (Admin/Staff)
  • deviceType: turnstile o premium
{
"data": [
{
"id": 1234567890,
"name": "Juan Pérez",
"registration": "1234567890"
}
]
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].devices[':deviceType'].users.$get({
param: { deviceType: 'premium' }
})

Configura un dispositivo para operar en modo online. El dispositivo comenzará a enviar eventos de acceso al webhook del API para validación en tiempo real.

  • URL: /api/v1/access-control/devices/:deviceType/configure
  • Método: POST
  • Autenticación Requerida: Sí (Admin)
  • deviceType: turnstile o premium
{
"message": "Dispositivo \"turnstile\" configurado en modo online"
}
import { hcWithType } from '@vitality-gym/api/client'
const client = hcWithType('http://localhost:3000')
const res = await client.api.v1['access-control'].devices[':deviceType'].configure.$post({
param: { deviceType: 'turnstile' }
})

Estos endpoints no requieren autenticación. Son llamados directamente por los dispositivos ControlID cuando ocurre un evento de acceso.

Endpoint principal del monitor. Recibe un evento de identificación del dispositivo, valida la membresía del usuario en tiempo real, y responde con la decisión de acceso.

  • URL: /api/v1/access-control/monitor/dao
  • Método: POST
  • Autenticación Requerida: No (llamado por el dispositivo)

Cuerpo de la Petición (enviado por el dispositivo)

Section titled “Cuerpo de la Petición (enviado por el dispositivo)”
{
"user_id": 1234567890,
"event": 1
}
{
"response": 1,
"message": "Acceso permitido"
}
Valor de responseSignificado
1Acceso permitido
0Acceso denegado

Endpoint de keepalive para monitorear que los dispositivos están activos.

  • URL: /api/v1/access-control/monitor/device_is_alive
  • Método: POST
  • Autenticación Requerida: No (llamado por el dispositivo)
{
"ok": true
}

  1. Crear usuario + PIN: POST /enroll/:userProfileId → Registra en ambos dispositivos
  2. Captura facial: POST /enroll/:userProfileId/face → El usuario se para frente a la Talanquera → La imagen se copia automáticamente al dispositivo Premium
  1. El usuario se identifica en un dispositivo (rostro o PIN)
  2. El dispositivo envía un evento a POST /monitor/dao
  3. La API verifica la membresía del usuario en la base de datos
  4. La API responde con 1 (permitido) o 0 (denegado)
  5. El dispositivo ejecuta la acción correspondiente
VariableDescripciónEjemplo
CONTROLID_TURNSTILE_IPIP del dispositivo Talanquera (vía Tailscale/RPI)100.x.x.x:80
CONTROLID_TURNSTILE_LOGINLogin del dispositivo Talanqueraadmin
CONTROLID_TURNSTILE_PASSWORDPassword del dispositivo Talanqueraadmin
CONTROLID_PREMIUM_IPIP del dispositivo Premium (vía Tailscale/RPI)100.x.x.x:81
CONTROLID_PREMIUM_LOGINLogin del dispositivo Premiumadmin
CONTROLID_PREMIUM_PASSWORDPassword del dispositivo Premiumadmin
CONTROLID_API_CALLBACK_URLURL del API para el Monitor (alcanzable desde los dispositivos)http://100.x.x.x:3000