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:
- Empleado coloca dedo en sensor del dispositivo móvil
- App captura template biométrico
- Compara con template almacenado en servidor (encriptado)
- Si match >= 70%: Registro exitoso
- 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:
- Empleado mira a cámara frontal del dispositivo
- App captura foto y extrae características faciales
- Compara con foto almacenada en servidor
- Si match >= 80%: Registro exitoso
- 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:
- Empleado muestra código QR personal (credencial o app propia)
- Residente escanea con app
- Sistema valida QR contra base de datos
- 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:
- Residente busca empleado en lista
- Selecciona nombre
- Toma foto obligatoria del empleado
- 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 asistenciasuspended: 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:
- Al dar de alta empleado, mostrar aviso de privacidad
- Empleado firma consentimiento digital
- Consentimiento se almacena con timestamp y firma digital
- 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
- 📄 RF-HR-001: Empleados y Cuadrillas
- 📄 RF-HR-003: Costeo de Mano de Obra
- 📐 ET-HR-002: Implementación Biométrica
- 📱 US-HR-002: App Móvil de Asistencia
Estándares y Regulaciones
- LFPDPPP: Ley Federal de Protección de Datos Personales
- ISO/IEC 24745: Biometric Information Protection
- NIST: Biometric Standards
📅 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