Skip to main content

Overview

Kiosk mode enables employees to register their attendance (clock in/out, breaks) through dedicated self-service terminals deployed at work locations. Each kiosk is associated with a specific unit (work location) and can be configured with security features like photo verification and access codes.

What is a Kiosk?

A kiosk in Integra is a physical terminal (tablet, computer, or dedicated device) that:
  • Runs the kiosk client application
  • Allows employees to register attendance without authentication
  • Captures optional photos for verification
  • Operates at a specific unit (work location)
  • Can be configured remotely from the admin panel
Kiosks operate in public mode - they don’t require user login. Instead, employees identify themselves with their employee ID or PIN code.

Kiosk Configuration

Unit-Based Configuration

Each kiosk is tied to a unit entity with kiosk-specific settings:
@Entity
@Table(name = "unidad")
public class UnidadEntity {
    // ... basic unit fields ...
    
    // Kiosk configuration
    @ColumnDefault("1")
    @Column(name = "requiere_camara")
    private Boolean requiereCamara;
    
    @Size(max = 5)
    @Column(name = "codigo_autorizacion_kiosco", length = 5)
    private String codigoAutorizacionKiosco;
    
    @Column(name = "requiere_codigo")
    private Boolean requiereCodigo;
    
    @ColumnDefault("1")
    @Column(name = "version_kiosco")
    private Integer versionKiosco;
    
    @Column(name = "tiempo_compensacion")
    private LocalTime tiempoCompensacion;
    
    @Column(name = "tiempo_espera_kiosco")
    private Integer tiempoEsperaKiosco;
}
Configuration fields:
  • requiereCamara: Whether photo capture is mandatory
  • codigoAutorizacionKiosco: One-time setup code for kiosk initialization
  • requiereCodigo: Whether kiosk is requesting an authorization code
  • versionKiosco: Configuration version for client sync
  • tiempoCompensacion: Time buffer for early/late punches
  • tiempoEsperaKiosco: Photo capture delay in milliseconds

Kiosk Management API

Listing Kiosks

Get all available kiosk units:
@GetMapping
public ResponseEntity<ResponseData<List<Unidad>>> obtenerUnidadesKiosco() {
    return ResponseEntity.ok(
        ResponseData.of(queryService.obtenerUnidadesKiosco(), "Unidades Kiosco")
    );
}
Endpoint: GET /kioscos Public access: ✅ No authentication required

Get Kiosk Details

Retrieve specific kiosk configuration:
@GetMapping("/{id}")
public ResponseEntity<ResponseData<Unidad>> obtenerUnidadKiosco(@PathVariable Integer id) {
    return ResponseEntity.ok(
        ResponseData.of(queryService.obtenerUnidadKiosco(id), "Unidad Kiosco")
    );
}
Endpoint: GET /kioscos/{id} Public access: ✅ No authentication required

Kiosk Setup Process

1. Generate Configuration Code

Administrator generates a one-time setup code:
@PatchMapping("/{id}/codigo")
public ResponseEntity<ResponseData<String>> generarCodigoConfigUnSoloUso(@PathVariable Integer id) {
    String codigo = commandService.generarCodigoConfig(id);
    return ResponseEntity.ok(
        ResponseData.of(codigo, "Se ha procesado la confirmación")
    );
}
Endpoint: PATCH /kioscos/{id}/codigo Authorization: 🔒 Admin only Response:
{
  "success": true,
  "data": "A7B2C",
  "message": "Se ha procesado la confirmación"
}
The code is stored in codigoAutorizacionKiosco field and is valid for a single use.

2. Kiosk Uses Setup Code

The kiosk client consumes the code to complete setup:
@PostMapping("/{id}/codigos/{codigo}/usar")
public ResponseEntity<ResponseData<Void>> usarCodigoConfiguracion(
    @PathVariable Integer id, 
    @PathVariable String codigo) {
    commandService.usarCodigoConfig(id, codigo);
    return ResponseEntity.ok(ResponseData.of(true, "Código autorizado"));
}
Endpoint: POST /kioscos/{id}/codigos/{codigo}/usar Public access: ✅ No authentication required Process:
  1. Kiosk sends unit ID and setup code
  2. System validates code matches the unit’s codigoAutorizacionKiosco
  3. Code is consumed (can only be used once)
  4. Kiosk receives configuration data
  5. Kiosk is ready for use

3. Ongoing Configuration Sync

When configuration changes occur, the versionKiosco field is incremented. Kiosk clients check this version to know when to refresh their configuration.

Remote Code Requests

Kiosk Requests Access Code

If a kiosk needs re-authorization, it can request a code:
@PatchMapping("/{id}/requiere-codigo")
public ResponseEntity<ResponseData<Void>> solicitarCodigo(@PathVariable Integer id) {
    commandService.solicitarCodigo(id);
    return ResponseEntity.ok(ResponseData.of(true, "Solicitud enviada"));
}
Endpoint: PATCH /kioscos/{id}/requiere-codigo Public access: ✅ No authentication required This sets requiereCodigo = true on the unit, which:
  • Displays a notification in the admin panel
  • Prevents the kiosk from processing attendance
  • Requires admin intervention to generate a new code

Admin Cancels Code Request

Administrator cancels a pending code request:
@DeleteMapping("/{id}/requiere-codigo")
public ResponseEntity<ResponseData<Void>> cancelarCodigo(@PathVariable Integer id) {
    commandService.cancelarRequiereCodigo(id);
    return ResponseEntity.ok(ResponseData.of(true, "Solicitud enviada"));
}
Endpoint: DELETE /kioscos/{id}/requiere-codigo Authorization: 🔒 Admin only

Camera Configuration

Enable/Disable Camera

Toggle photo verification requirement:
@PatchMapping("/{id}/camara")
public ResponseEntity<ResponseData<Void>> actualizarUsoCamara(
    @PathVariable Integer id, 
    @RequestParam(name = "estatus", required = true) Boolean estatus) {
    commandService.actualizarUsoCamara(id, estatus);
    return ResponseEntity.ok(
        ResponseData.of(true, "Estatus actualizado correctamente")
    );
}
Endpoint: PATCH /kioscos/{id}/camara?estatus={true|false} Authorization: 🔒 Admin only Use cases:
  • Privacy regulations requiring opt-in
  • Camera hardware failure
  • Temporary suspension of photo verification
  • Testing without camera

Time Configuration

Photo Capture Delay

Configure how long the camera waits before capturing:
@PatchMapping("/tiempo-captura")
public ResponseEntity<ResponseData<Void>> actualizarTiempoEspera(@RequestParam Integer tiempoEspera) {
    commandService.actualizarTiempoEspera(tiempoEspera);
    return ResponseEntity.ok(
        ResponseData.of(true, "Tiempo de espera actualizado correctamente")
    );
}
Endpoint: PATCH /kioscos/tiempo-captura?tiempoEspera={milliseconds} Authorization: 🔒 Authenticated Purpose:
  • Give employees time to position themselves
  • Improve photo quality
  • Prevent accidental captures

Compensation Time

Set time buffer for early/late attendance:
@PatchMapping("/{id}/compensacion")
public ResponseEntity<ResponseData<Void>> actualizarCompensacion(
    @PathVariable Integer id, 
    @RequestParam LocalTime compensacion) {
    commandService.actualizarCompensacion(id, compensacion);
    return ResponseEntity.ok(
        ResponseData.of(true, "Tiempo de compensación actualizado correctamente")
    );
}
Endpoint: PATCH /kioscos/{id}/compensacion?compensacion={HH:mm:ss} Authorization: 🔒 Authenticated Example: Setting compensation to 00:05:00 allows employees to clock in up to 5 minutes late without penalty.

Attendance Registration Flow

Employee Workflow

  1. Employee arrives at kiosk
    • Kiosk displays interface
    • Employee enters employee ID or PIN
  2. Kiosk validates employee
    • Checks if employee exists
    • Verifies employee status is active
  3. Photo capture (if enabled)
    • Camera activates with countdown (tiempoEsperaKiosco)
    • Photo is captured
    • Photo stored at server
  4. Attendance recorded
    • POST to /asistencia/iniciar or /asistencia/finalizar
    • Kiosk unit ID included in request
    • Server validates against employee’s assigned unit
  5. Confirmation displayed
    • Success/error message shown
    • Employee can proceed

Cross-Unit Registration

Employees can register at kiosks outside their assigned unit. The system tracks:
@Entity
@Table(name = "cruce_empleado_kiosco")
public class CruceEmpleadoKiosco {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Integer id;
    
    @NotNull
    private Integer asistenciaId;
    
    @Lob
    private String accion;  // "iniciar", "finalizar", etc.
    
    @Size(max = 255)
    private String pathImg;  // Photo path
    
    private LocalDateTime fecha;
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "unidad_registro_id")
    private UnidadEntity unidadRegistro;  // Where they actually clocked in
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "unidad_esperada_id")
    private UnidadEntity unidadEsperada;  // Where they should have been
    
    @ManyToOne(fetch = FetchType.LAZY)
    @JoinColumn(name = "empleado_id")
    private EmpleadoEntity empleado;
}
This enables:
  • Tracking of employees working at different locations
  • Identification of location mismatches
  • Auditing of cross-location activity
  • Reporting on unit coverage

Querying Cross-Unit Activity

@GetMapping()
public ResponseEntity<ResponseData<?>> obtenerCruceUnidades(@Valid CruceKioscoFiltroDTO filtro) {
    var cruces = service.buscarPorFiltros(filtro);
    return ResponseEntity.ok(
        ResponseData.of(cruces, "Cruce de empleados en unidades de registro")
    );
}
Endpoint: GET /cruce-kiosco Filter by:
  • Date range
  • Employee
  • Unit (expected vs actual)
  • Action type

Security Considerations

Public Endpoints

Kiosk endpoints are intentionally public to support unattended operation:
  • No user login required
  • No authentication token needed
  • Kiosk identifies itself by unit ID
Because kiosk endpoints are public, they should be protected at the network level. Consider:
  • Restricting access to local network only
  • Using VPN for remote locations
  • Implementing rate limiting
  • Monitoring for abuse

Photo Storage

Photos are stored as file paths:
  • Server manages file storage location
  • Paths are relative to configured storage directory
  • Access to photo files should be restricted
  • Consider retention policies for GDPR compliance

Code Security

Setup codes (codigoAutorizacionKiosco):
  • Are single-use only
  • Expire after first use
  • Should be short-lived (generate and use quickly)
  • Are alphanumeric (5 characters)

Best Practices

Deployment

  1. Dedicated devices: Use tablets or computers in kiosk mode (locked-down OS)
  2. Physical security: Mount devices securely to prevent tampering
  3. Network isolation: Separate kiosk network from corporate network
  4. Auto-recovery: Configure devices to reboot and reconnect automatically
  5. Monitoring: Track kiosk online/offline status

Configuration

  1. Photo verification: Enable for high-security environments
  2. Compensation time: Set based on company policy and unit needs
  3. Capture delay: 3-5 seconds typically provides good results
  4. Version tracking: Increment version when configuration changes

User Experience

  1. Clear instructions: Display simple, visual instructions on kiosk
  2. Feedback: Provide immediate confirmation of successful registration
  3. Error handling: Show helpful error messages in local language
  4. Accessibility: Ensure kiosk height and interface work for all employees
  5. Offline mode: Consider offline capability for network outages

Maintenance

  1. Regular checks: Test kiosks periodically for camera/network issues
  2. Update process: Have a rollback plan for kiosk software updates
  3. Code rotation: Regenerate setup codes if security is compromised
  4. Clean cameras: Physical maintenance for photo quality

Build docs developers (and LLMs) love