Inmutabilidad y trazabilidad de registros

Versión 2.0 — 10 de junio de 2026

Resumen legal: El artículo 34.9 del Estatuto de los Trabajadores exige que el registro de jornada sea fiable. Nuestro sistema aplica cuatro capas de protección criptográfica —hash chain por trabajador, sellos diarios, certificación mensual y logs append-only en GitHub— para garantizar que una vez certificado un mes, nadie —ni siquiera nosotros— puede modificar los datos sin dejar rastro matemático.

1. ¿Por qué la inmutabilidad importa?

El RD-Ley 8/2019 obliga a todas las empresas a registrar la jornada diaria de cada trabajador y a conservar esos registros durante 4 años. Pero registrar no basta: los datos deben ser fiables. En un juicio o inspección, el empresario debe poder demostrar que los registros reflejan la realidad y que no han sido manipulados posteriormente.

Jornatrack resuelve esto con un sistema de cuatro capas que van desde el registro individual hasta la blockchain de Bitcoin:

  • Hash chain por trabajador: cada fichaje se encadena criptográficamente con el anterior del mismo trabajador.
  • Sello diario: cada día se genera una instantánea hashada de todos los registros e incidencias.
  • Certificación mensual: al cerrar el mes se genera un hash SHA-256 global sellado con OpenTimestamps.
  • Logs append-only en GitHub: cada operación de escritura se guarda en un repositorio externo que no se puede borrar sin dejar huella.

2. Las cuatro capas de protección

Capa 1 — Hash chain por trabajador

Cada vez que un trabajador fichaje, el sistema calcula dos hashes:

  • hashVerificacion: SHA-256 de los datos críticos del registro (fecha, horas, tipo, etc.). Si cambia cualquier dato, este hash cambia.
  • hashCadena: SHA-256 del hash anterior del mismo trabajador + el hashVerificacion actual. Esto crea una cadena criptográfica: romper un eslabón rompe todos los siguientes.

Gracias a esto, si un atacante modifica un fichaje del día 5, la cadena se rompe en el día 6, 7, 8… y el sistema lo detecta inmediatamente.

Capa 2 — Sello diario (SelloDiario)

Cada día a las 00:05 UTC, un proceso automático genera una instantánea determinista de todos los registros horario e incidencias del día anterior para cada empresa. De esa instantánea se calcula un hash SHA-256 y se sella con OpenTimestamps. El resultado se guarda en:

  • La base de datos (tabla SelloDiario), con el hash, la URL de GitHub y el estado cerrado.
  • Un repositorio privado de GitHub, en la ruta {empresa-slug}/{año}/{mes}/{día}.ots.

¿Por qué es importante? El sello diario proporciona granularidad intermedia. Si alguien manipula datos del día 15 de un mes, el sello diario del día 15 ya no coincidirá con el hash recalculado, aunque el mes aún no esté cerrado. Además, al estar sellado con OpenTimestamps, demuestra que esa instantánea existía en esa fecha concreta, impidiendo retrodatación.

Capa 3 — Certificación mensual (CertificacionMensual)

El día 10 del mes siguiente (o manualmente antes), el administrador cierra el periodo. El sistema:

  1. Genera un snapshot JSON determinista del mes completo: todos los registros, incidencias, bajas médicas, vacaciones, correcciones, logs de auditoría, configuración de la empresa y trabajadores activos.
  2. Calcula el hash SHA-256 de ese snapshot.
  3. Genera un sello de tiempo .ots con OpenTimestamps, anclándolo en la blockchain de Bitcoin.
  4. Sube el archivo .ots y el hash a GitHub.
  5. Guarda la certificación en la base de datos con estado CERRADO.

Este hash es la huella digital legal del mes. Si se modifica cualquier dato posteriormente, el hash recalculado ya no coincide.

Capa 4 — Logs append-only en GitHub

Cada operación de escritura (crear, editar o eliminar un registro) se loguea simultáneamente en:

  • La base de datos PostgreSQL (tabla LogAuditoria), con datos anteriores, datos nuevos, IP, User-Agent, usuario y timestamp.
  • Un repositorio privado de GitHub, en la ruta logs/{empresa-slug}/{año}/{mes}/{día}/{registroId}_{timestamp}_{hash}.json.

¿Por qué GitHub? Incluso si un atacante con acceso a la base de datos borra los logs locales, los archivos en GitHub siguen existiendo. Cada archivo tiene su propio hash y forma parte del historial de commits. Borrarlos requería modificar el historial de Git, lo cual deja una huella visible y técnicamente compleja.

3. ¿Cómo se comprueba que un mes NO ha sido modificado?

El sistema ofrece tres niveles de verificación, del más simple al más riguroso:

Nivel 1 — Verificación desde el panel de administración
  1. Ir a Dashboard Admin → Certificaciones de Inmutabilidad.
  2. Expandir el mes que se quiere verificar.
  3. Observar los dos hashes:
    • Hash Sellado (Cierre): el SHA-256 calculado el día del cierre.
    • Hash Actual (Verificación): el SHA-256 recalculado en tiempo real con los datos actuales.
  4. Si ambos coinciden, aparece ✅ Coincide con el hash sellado. El mes no ha sido modificado.
  5. Si difieren, aparece ❌ NO COINCIDE. Expandir la sección de discrepancia para ver el detalle.
Nivel 2 — Verificación técnica avanzada (API)
  1. Llamar a GET /api/admin/certificaciones/discrepancia?year=YYYY&month=MM.
  2. Revisar el campo coinciden (true/false) y alertaNivel (OK / ADVERTENCIA / CRITICO).
  3. Descargar el snapshot completo con GET /api/admin/certificaciones/snapshot?year=YYYY&month=MM.
  4. Calcular el SHA-256 del snapshot localmente (p. ej. sha256sum snapshot.json) y compararlo con el hash sellado.
Nivel 3 — Verificación del sello OpenTimestamps (blockchain Bitcoin)
  1. En la tarjeta del mes, hacer click en Sello OTS (blockchain).
  2. El sistema descarga el archivo .ots desde GitHub y verifica que el sello de tiempo es válido contra la red Bitcoin.
  3. Si es válido, demuestra que el hash existía en una fecha concreta (la del cierre), probando que los datos no se han retrodatado.
  4. Manualmente: descargar el .ots desde el enlace Ver .ots en GitHub y ejecutar ots verify archivo.ots con la CLI de OpenTimestamps.

4. ¿Qué pasa si hay anexos o correcciones después del cierre?

Un mes cerrado admite modificaciones únicamente a través de anexos certificados. Cada anexo genera un nuevo hash, un nuevo sello OTS y se sube a GitHub. Por tanto, la discrepancia de hash del mes principal es esperada y legal cuando existen anexos documentados.

Anexo tipo CORRECCION

Se genera cuando el administrador aprueba una corrección post-cierre (p. ej., un trabajador olvidó fichar y se corrige posteriormente). Incluye el motivo, quién lo autorizó y el hash del JSON de cambios.

Anexo tipo JUDICIAL

Se genera por orden judicial o administrativa. Tiene el mismo tratamiento criptográfico que un anexo normal, pero su motivo indica que proviene de una resolución externa.

Regla clave: Si el sistema detecta discrepancia pero hay anexos documentados, muestra una ⚠️ ADVERTENCIA. Esto significa que el mes fue modificado, pero cada cambio está justificado, firmado y sellado. Si la discrepancia aparece como 🚨 CRÍTICO y no hay anexos, se trata de una alteración no documentada.

5. ¿Cómo revisar un fichaje concreto en caso de queja o denuncia?

Cuando un trabajador, inspector de trabajo o juez cuestiona un fichaje específico, se debe seguir una cadena de evidencia única e irrepetible:

  1. Obtener el ID del registro. Desde el panel de administración (Dashboard Admin → Registros) o mediante la API: GET /api/admin/registros?trabajadorId=XXX&fecha=YYYY-MM-DD.
  2. Consultar los datos inmutables del registro. Cada RegistroHorario almacena hashVerificacion (SHA-256 de sus datos críticos) y hashCadena (encadenado con el registro anterior del mismo trabajador). Estos campos se muestran en el detalle del registro si el sistema de hash chains estaba activo cuando se creó.
  3. Verificar la cadena de hash del trabajador. Ir a Certificaciones → Discrepancia del mes correspondiente. Si el trabajador aparece en "Cadenas de hash rotas", algún registro suyo fue alterado tras el cierre. Si no aparece, su cadena es íntegra desde el primer día hasta el día del registro.
  4. Auditoría de cambios sobre ese registro. En Dashboard Admin → Auditoría y Logs, buscar por acción UPDATE o DELETE y localizar el registroId. Cada log muestra: datos anteriores vs datos nuevos, IP, User-Agent, usuario que hizo el cambio y timestamp exacto.
  5. Verificar logs append-only en GitHub. Cada operación de escritura se guarda en logs/{empresa-slug}/{año}/{mes}/{día}/{registroId}_{timestamp}_{hash}.json dentro del repositorio privado de GitHub. El log tiene su propio hash SHA-256 y es append-only: no se puede borrar sin modificar el historial de commits de Git.
  6. Evidencia de geolocalización y dispositivo (si aplica). En los logs de auditoría de CREATE/UPDATE, revisar ubicacionEntrada / ubicacionSalida (latitud, longitud, precisión en metros) y ipEntrada / ipSalida junto con userAgentEntrada / userAgentSalida.

6. ¿Cómo demostrar que no se ha modificado (o seguir el hilo si sí se modificó)?

Esta es la prueba estrella ante un inspector de trabajo o un juez. Se basa en la imposibilidad matemática de alterar un hash SHA-256 sin que se note.

Escenario A: "El mes está íntegro, no se tocó nada"

  1. Mostrar la pantalla de Certificaciones con el mes en estado ✅ Íntegro.
  2. El hash sellado coincide con el hash actual. El JSON determinista del mes es idéntico al día del cierre.
  3. Mostrar el Sello OTS verificado: prueba que el hash existía en blockchain Bitcoin en la fecha de cierre, por lo que no se pudo inventar después.
  4. Mostrar que no hay anexos en ese mes (sección Anexos vacía).
  5. Mostrar que las cadenas de hash por trabajador están intactas (ningún trabajador aparece en "Cadenas rotas").
  6. Conclusión legal: los datos están exactamente igual que el día del cierre. Cualquier intento de modificación habría roto el hash, la cadena o ambos.

Escenario B: "Hubo una corrección post-cierre, pero está documentada legalmente"

  1. Mostrar la pantalla de Certificaciones con el mes en estado ⚠️ ADVERTENCIA (hash difiere, pero hay anexos).
  2. Expandir la sección de Anexos. Cada anexo muestra: tipo (CORRECCION o JUDICIAL), motivo, hash del anexo y fecha de creación.
  3. Mostrar el registro modificado en Registros con su motivoModificacionAdmin, fechaModificacionAdmin y modifiedBy.
  4. Mostrar el log de auditoría del cambio con IP, User-Agent y usuario responsable.
  5. Mostrar el log en GitHub correspondiente al cambio (misma fecha/hora, mismo registroId).
  6. Conclusión legal: la modificación fue detectada, documentada, justificada y sellada. No es una alteración oculta; es una corrección legalmente trazable.

Escenario C: "Alguien alteró datos sin dejar rastro" (la peor pesadilla)

  1. Si alguien modifica directamente la BD (bypass de la app), el hash mensual ya no coincidirá. Al verificar integridad aparece 🚨 CRÍTICO.
  2. El sistema detectará registros modificados después del cierre sin anexos asociados. Aparecerán en rojo con detalle de campos, motivo y quién los modificó (si fue vía app).
  3. Si el atacante también borra logs de auditoría en PostgreSQL, los logs append-only en GitHub siguen existiendo. Cada operación está en un archivo JSON con hash propio en un repo de solo escritura.
  4. Si el atacante intenta recalcular hashes para encajar, la cadena de hashes por trabajador se rompe porque cada hashCadena depende del anterior (encadenamiento criptográfico).
  5. Conclusión legal: cualquier manipulación deja al menos una de estas huellas —hash roto, cadena rota, log faltante en BD pero presente en GitHub, o discrepancia de OTS. Es matemáticamente inviable borrar todas las huellas sin tener acceso simultáneo a BD, GitHub, blockchain Bitcoin y todos los backups.

7. Verificación independiente paso a paso

Cualquier parte interesada —trabajador, abogado, juez o inspector— puede verificar la integridad sin depender de nosotros:

  1. Descargar el snapshot mensual desde el panel de administración o solicitarlo al titular del tratamiento.
  2. Calcular el hash SHA-256 del archivo con cualquier herramienta estándar (shasum -a 256 snapshot.json en Linux/Mac, o PowerShell Get-FileHash -Algorithm SHA256 en Windows).
  3. Descargar la prueba OpenTimestamps (.ots) asociada desde el enlace público de GitHub.
  4. Verificar la prueba con la herramienta oficial: ots verify archivo.ots.
  5. Si el hash calculado coincide con el sellado y el OTS es válido, el documento no ha sido alterado desde el cierre.

Nota: para acceder a los repositorios privados de GitHub se requiere autorización del cliente. El titular del tratamiento (la empresa) es quien debe facilitar el acceso en caso de litigio.

8. Plataformas intervinientes

PlataformaFunciónUbicación datos
Vercel Inc.Alojamiento y ejecución de la aplicaciónUnión Europea (Frankfurt)
Supabase Inc.Base de datos PostgreSQL y almacenamiento de objetosUnión Europea (Frankfurt)
GitHub Inc.Almacenamiento append-only de logs, sellos diarios, certificaciones mensuales y anexosEstados Unidos (SCC)
OpenTimestampsSellado de tiempo descentralizado en blockchain de BitcoinDistribuido globalmente (protocolo público)
Stripe Inc.Pasarela de pagosEstados Unidos (SCC)

Estas plataformas actúan como subencargados de tratamiento conforme al Contrato de Encargado de Tratamiento (DPA).

9. Limitaciones y responsabilidades

  • El sistema garantiza la inmutabilidad posterior a la certificación, pero no puede impedir que un administrador modifique datos antes de cerrar el mes. Todas las modificaciones previas quedan registradas en el log de auditoría y en GitHub.
  • La prueba de OpenTimestamps demuestra la existencia del hash en una fecha determinada, pero no verifica la veracidad de los datos originales. La veracidad depende del correcto uso de la plataforma por parte del cliente y de los trabajadores.
  • El Prestador no asume la responsabilidad del cumplimiento efectivo por parte del cliente del deber legal de registro de jornada ni de la custodia de los registros durante los 4 años exigidos.
  • Los sellos diarios dependen de que el cron se ejecute correctamente. Si el cron falla, el sello de ese día no se genera, pero esto no invalida los sellos de días anteriores ni la certificación mensual.

10. Documentación técnica complementaria

Para auditorías técnicas o periciales informáticas, se dispone del siguiente documento detallado:

AUDITORIA_TECNICA.html

Documento técnico completo con el checklist de verificación de inmutabilidad, comandos API, explicación de algoritmos de hash chain, sellos diarios, certificación mensual, anexos post-cierre y cheat sheet de endpoints para auditoría rápida.

Ubicación: raíz del repositorio de código fuente (disponible para el cliente bajo solicitud).

11. Documentación relacionada