erp-construccion/docs/02-definicion-modulos/MAI-007-rrhh-asistencias/requerimientos/RF-HR-002-asistencia-biometrica.md

16 KiB

RF-HR-002: Sistema de Asistencia con Biométrico

📋 Metadata

Campo Valor
ID RF-HR-002
Módulo RRHH y Asistencias
Prioridad P0 - Crítica
Estado 🚧 Planificado
Versión 1.0
Fecha creación 2025-11-17
Última actualización 2025-11-17

🔗 Referencias

Especificación Técnica

📐 ET-HR-002: Asistencia Biométrica Implementation

Implementación

🗄️ Database:

  • Ubicación: apps/database/ddl/schemas/hr/tables/02-attendance_records.sql
  • Tabla: hr.attendance_records
  • ENUM: attendance_method (biometric_fingerprint, biometric_facial, qr_code, manual, gps)

💻 Backend:

  • Módulo: apps/backend/src/modules/hr/attendance/
  • Service: AttendanceService, BiometricService
  • API: /api/hr/attendance

📱 App Móvil:

  • Módulo: apps/mobile/src/features/attendance/
  • Componentes: Biometric scanner, QR scanner, GPS validator

Reusado de GAMILIT

♻️ Concepto similar: Tracking de progreso de estudiantes Adaptación: Alta - Funcionalidad completamente nueva con biométrico


📝 Descripción del Requerimiento

Contexto

En proyectos de construcción, el control de asistencia del personal es crítico para:

  • Costeo real de mano de obra: Saber exactamente qué días trabajó cada empleado
  • Cumplimiento legal: IMSS requiere evidencia de días trabajados
  • Prevención de fraude: Evitar "aviadores" (trabajadores que cobran sin trabajar)
  • Seguridad: Saber quién está presente en obra (en caso de accidentes)
  • Productividad: Relacionar avances con horas-hombre trabajadas

Problemática actual (manual):

  • Listas en papel propensas a error y manipulación
  • Imposible verificar ubicación del empleado
  • Difícil auditar registros
  • Tiempo perdido pasando lista cada mañana
  • Riesgo de firmas falsas o doble registro

Solución: Sistema de asistencia digital con validación biométrica (huella dactilar o facial) desde app móvil, con validaciones automáticas de GPS y horario.


🎯 Requerimientos Funcionales

RF-HR-002.1: Métodos de Registro de Asistencia

El sistema DEBE soportar múltiples métodos de registro con la siguiente prioridad:

1. Biométrico - Huella Dactilar (Método Preferido)

Tecnología: react-native-biometrics

Proceso:

  1. Empleado coloca dedo en sensor del dispositivo móvil
  2. App captura template biométrico
  3. Compara con template almacenado en servidor (encriptado)
  4. Si match >= 70%: Registro exitoso
  5. Si match < 70%: Solicitar re-intento (max 3 intentos)

Ventajas:

  • Rapidez: <3 segundos por registro
  • Alta precisión (>99%)
  • No requiere contacto adicional (device ya tiene sensor)
  • Funciona offline (template en caché local)

Desventajas:

  • ⚠️ No todos los dispositivos tienen sensor de huella
  • ⚠️ Requiere enrollment previo (1ra vez)

2. Biométrico - Reconocimiento Facial (Alternativa)

Tecnología: expo-camera + ML Kit / Vision API

Proceso:

  1. Empleado mira a cámara frontal del dispositivo
  2. App captura foto y extrae características faciales
  3. Compara con foto almacenada en servidor
  4. Si match >= 80%: Registro exitoso
  5. Si match < 80%: Fallback a QR o manual

Ventajas:

  • No requiere contacto físico
  • Funciona en cualquier dispositivo con cámara frontal
  • Buena precisión con buena iluminación

Desventajas:

  • ⚠️ Requiere buena iluminación
  • ⚠️ Puede fallar con cascos/lentes/cubrebocas
  • ⚠️ Más lento que huella (~5-7 segundos)

3. QR Code (Fallback Principal)

Tecnología: react-native-qrcode-scanner

Proceso:

  1. Empleado muestra código QR personal (credencial o app propia)
  2. Residente escanea con app
  3. Sistema valida QR contra base de datos
  4. Registro exitoso con foto opcional

Ventajas:

  • Funciona en cualquier dispositivo con cámara
  • Rápido (~2 segundos)
  • No requiere enrollment previo

Desventajas:

  • ⚠️ Requiere que empleado porte credencial
  • ⚠️ QR puede ser falsificado (mitigado con foto adicional)

Generación de QR:

QR Content: {employeeId}|{constructoraId}|{hash}
Hash: HMAC-SHA256(employeeId + constructoraId + SECRET_KEY)

4. Lista Manual (Fallback Secundario)

Proceso:

  1. Residente busca empleado en lista
  2. Selecciona nombre
  3. Toma foto obligatoria del empleado
  4. Confirma registro

Ventajas:

  • Siempre funciona
  • Útil para visitantes o personal temporal

Desventajas:

  • ⚠️ Más lento (~10-15 segundos por persona)
  • ⚠️ Requiere foto para validación

RF-HR-002.2: Validaciones Automáticas

El sistema DEBE aplicar las siguientes validaciones en tiempo real:

1. Validación de GPS (Geolocalización)

Objetivo: Verificar que el empleado esté físicamente en la obra

Regla:

IF distancia(ubicación_empleado, ubicación_obra) <= 100 metros
THEN validación_gps = PASS
ELSE validación_gps = WARNING (permitir override manual)

Configuración:

  • Radio por defecto: 100 metros
  • Radio configurable por obra (50m - 500m)
  • Precisión mínima requerida del GPS: 20 metros

Casos especiales:

  • GPS desactivado: Advertencia + Permitir registro con nota
  • GPS impreciso: Advertencia + Permitir registro
  • Fuera de radio: Advertencia + Requiere justificación del residente

Implementación:

// Haversine formula para calcular distancia
function calculateDistance(
  lat1: number, lon1: number,
  lat2: number, lon2: number
): number {
  const R = 6371e3; // Radio de la Tierra en metros
  const φ1 = lat1 * Math.PI/180;
  const φ2 = lat2 * Math.PI/180;
  const Δφ = (lat2-lat1) * Math.PI/180;
  const Δλ = (lon2-lon1) * Math.PI/180;

  const a = Math.sin(Δφ/2) * Math.sin(Δφ/2) +
            Math.cos(φ1) * Math.cos(φ2) *
            Math.sin(Δλ/2) * Math.sin(Δλ/2);
  const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

  return R * c; // Distancia en metros
}

2. Validación de Horario (Jornada Laboral)

Objetivo: Detectar registros fuera de horario normal

Reglas:

Horario normal: 6:00 AM - 8:00 PM (configurable)

IF hora_registro BETWEEN 6:00 AND 8:00
THEN validación_horario = PASS
ELSE validación_horario = WARNING (permitir registro con nota)

Configuración por obra:

  • Horario de entrada permitido: 5:00 AM - 9:00 AM
  • Horario de salida permitido: 3:00 PM - 9:00 PM
  • Tolerancia de retraso: 15 minutos (sin penalización)

Casos especiales:

  • Hora extra: Registro fuera de horario requiere autorización previa
  • Turno nocturno: Validar contra horario de turno específico
  • Domingo/Festivo: Advertencia + Confirmar con residente

3. Validación de Estado del Empleado

Objetivo: Solo permitir registro de empleados activos y asignados

Reglas:

WHERE employee.status = 'active'
  AND employee.id IN (
    SELECT employee_id
    FROM project_employee_assignments
    WHERE project_id = {current_project_id}
      AND active = true
  )

Estados de empleado:

  • active: Puede registrar asistencia
  • suspended: No puede registrar (mensaje: "Empleado suspendido, contactar RRHH")
  • terminated: No puede registrar (mensaje: "Empleado dado de baja")
  • inactive: No puede registrar (mensaje: "Empleado inactivo")

4. Validación de Duplicados

Objetivo: Prevenir doble check-in sin check-out previo

Reglas:

IF existe registro check-in del día SIN check-out
THEN bloquear nuevo check-in (mensaje: "Ya tienes un registro activo. Debes hacer check-out primero")

Lógica:

SELECT COUNT(*) FROM hr.attendance_records
WHERE employee_id = {employee_id}
  AND project_id = {project_id}
  AND date = CURRENT_DATE
  AND check_out_time IS NULL
  AND status = 'active'

RF-HR-002.3: Tipos de Registro

1. Check-in (Entrada)

Cuándo: Al iniciar jornada laboral

Datos capturados:

  • Timestamp (fecha + hora)
  • Método de registro (biometric_fingerprint, biometric_facial, qr_code, manual)
  • GPS (latitud, longitud, precisión)
  • Foto (opcional, obligatoria si es manual)
  • Dispositivo usado (device_id)
  • Residente que registró (user_id)

Validaciones aplicadas:

  • GPS dentro de radio
  • Horario de entrada permitido
  • Empleado activo y asignado
  • Sin check-in previo activo

2. Check-out (Salida)

Cuándo: Al terminar jornada laboral

Datos capturados:

  • Timestamp de salida
  • GPS de salida
  • Horas trabajadas (calculadas automáticamente)

Validaciones aplicadas:

  • Existe check-in previo del día
  • Tiempo mínimo trabajado: 1 hora (evitar registros erróneos)
  • Horario de salida permitido

Cálculo de horas trabajadas:

const horasTrabajadas = (checkOutTime - checkInTime) / (1000 * 60 * 60); // En horas
const horasRedondeadas = Math.round(horasTrabajadas * 4) / 4; // Redondear a cuartos de hora

RF-HR-002.4: Modo Offline

Requisito: La app DEBE funcionar sin conexión a internet

Capacidades offline:

  • Registrar hasta 500 asistencias en cola local
  • Cache de lista de empleados de la obra (actualizado diariamente)
  • Cache de templates biométricos (encriptados)
  • Validaciones GPS y horario (usando hora local del dispositivo)
  • Indicador visual de registros pendientes de sincronización

Sincronización:

// Automática al detectar conexión
window.addEventListener('online', () => {
  syncPendingAttendances();
});

// Manual por botón
function syncNow() {
  if (navigator.onLine) {
    syncPendingAttendances();
  } else {
    showToast('Sin conexión. Sincronizará automáticamente al reconectar.');
  }
}

Resolución de conflictos:

  • Si existe registro duplicado en servidor: Usar el de menor timestamp
  • Si empleado fue dado de baja: Rechazar registro offline
  • Log de conflictos para auditoría

RF-HR-002.5: Seguridad y Privacidad

1. Almacenamiento de Datos Biométricos

Reglas:

  • NUNCA almacenar imagen de huella dactilar completa
  • Almacenar solo template hash (irreversible)
  • Templates encriptados en tránsito (HTTPS)
  • Templates encriptados en reposo (AES-256)

Formato de template:

interface BiometricTemplate {
  employeeId: string;
  templateHash: string; // SHA-256(template_raw)
  algorithm: 'FingerprintJS' | 'FaceNet';
  createdAt: Date;
  lastUsed: Date;
  encrypted: boolean;
}

2. Consentimiento del Empleado

Requisito: Obtener consentimiento explícito antes de capturar biométricos

Proceso:

  1. Al dar de alta empleado, mostrar aviso de privacidad
  2. Empleado firma consentimiento digital
  3. Consentimiento se almacena con timestamp y firma digital
  4. Sin consentimiento: Solo métodos no biométricos (QR, manual)

Texto de consentimiento (ejemplo):

"Autorizo a [Constructora] a capturar y almacenar mis datos biométricos
(huella dactilar y/o reconocimiento facial) con el único propósito de
registrar mi asistencia laboral. Entiendo que estos datos están protegidos
conforme a la Ley Federal de Protección de Datos Personales en Posesión
de los Particulares."

3. Retención de Datos

Política:

  • Registros de asistencia: Retener 5 años (requerimiento fiscal)
  • Templates biométricos: Eliminar a los 30 días de baja del empleado
  • Fotos: Retener 1 año, luego eliminar automáticamente

RF-HR-002.6: Reportes y Auditoría

1. Reporte de Asistencias Diarias

Contenido:

  • Lista de empleados con check-in/check-out del día
  • Horas trabajadas
  • Empleados faltantes (esperados pero sin registro)
  • Anomalías (GPS fuera de radio, horario inusual)

Formato: PDF, Excel


2. Reporte Mensual para Nómina

Contenido:

  • Días trabajados por empleado
  • Total de horas trabajadas
  • Horas extra (fuera de horario normal)
  • Faltas injustificadas

Exportación: Excel compatible con sistemas de nómina


3. Log de Auditoría

Registrar:

  • Todos los registros de asistencia
  • Intentos fallidos de biométrico
  • Overrides manuales de validaciones
  • Cambios en configuración (radio GPS, horarios)
  • Acceso a datos de asistencia

Criterios de Aceptación

AC-001: Métodos de Registro Funcionando

  • Biométrico (huella) funciona en dispositivos compatibles
  • Biométrico (facial) funciona como alternativa
  • QR Code scanner funciona correctamente
  • Registro manual con foto obligatoria funciona

AC-002: Validaciones Automáticas Activas

  • Validación GPS detecta empleado fuera de radio
  • Validación de horario detecta registros fuera de jornada
  • Validación de estado bloquea empleados inactivos
  • Validación de duplicados previene doble check-in

AC-003: Modo Offline Funcional

  • App registra asistencias sin conexión
  • Cola local almacena hasta 500 registros
  • Sincronización automática al reconectar
  • Indicador visual de registros pendientes

AC-004: Seguridad y Privacidad

  • Templates biométricos están encriptados
  • Consentimiento de empleado se obtiene antes de enrollment
  • Datos se eliminan según política de retención
  • Auditoría completa de accesos

AC-005: Reportes Disponibles

  • Reporte diario de asistencias
  • Reporte mensual para nómina
  • Exportación Excel funcional
  • Log de auditoría completo

🧪 Testing

Test Case 1: Registro con huella dactilar exitoso

test('Should register attendance with fingerprint', async () => {
  const employee = await createEmployee();
  await enrollFingerprint(employee.id);

  const attendance = await registerAttendance({
    employeeId: employee.id,
    projectId: 'project-123',
    method: 'biometric_fingerprint',
    gps: { lat: 19.4326, lon: -99.1332 },
    fingerprintTemplate: 'encrypted_template_hash'
  });

  expect(attendance.status).toBe('success');
  expect(attendance.method).toBe('biometric_fingerprint');
  expect(attendance.validations.gps).toBe('PASS');
});

Test Case 2: Validación GPS falla (fuera de radio)

test('Should warn when GPS is outside radius', async () => {
  const employee = await createEmployee();
  const project = await createProject({ gps: { lat: 19.4326, lon: -99.1332 }, radius: 100 });

  const result = await registerAttendance({
    employeeId: employee.id,
    projectId: project.id,
    gps: { lat: 19.5000, lon: -99.2000 } // ~10km away
  });

  expect(result.validations.gps).toBe('WARNING');
  expect(result.warnings).toContain('GPS outside work radius');
});

Test Case 3: Modo offline sincroniza correctamente

test('Should sync offline records when back online', async () => {
  await goOffline();

  const attendance1 = await registerAttendanceOffline({ employeeId: 'emp-1' });
  const attendance2 = await registerAttendanceOffline({ employeeId: 'emp-2' });

  expect(await getPendingSyncCount()).toBe(2);

  await goOnline();
  await syncPendingAttendances();

  expect(await getPendingSyncCount()).toBe(0);
  expect(await getServerAttendanceCount()).toBe(2);
});

📚 Referencias Adicionales

Documentos Relacionados

Estándares y Regulaciones


📅 Historial de Cambios

Versión Fecha Autor Cambios
1.0 2025-11-17 Tech Lead Creación inicial - Nueva funcionalidad

Documento: docs/01-fase-alcance-inicial/MAI-007-rrhh-asistencias/requerimientos/RF-HR-002-asistencia-biometrica.md Ruta relativa: MAI-007-rrhh-asistencias/requerimientos/RF-HR-002-asistencia-biometrica.md Épica: MAI-006 (RRHH, Asistencias y Nómina) Sprint: Sprint 9-10 (Semanas 13.5-16) Prioridad: P0 - Crítica