ums

ADR-0076: Almacenamiento UTC, Detección de Timezone del Browser y Resolución de Idioma

Estado: Aceptado
Fecha: 2026-06-02
Contexto: Plataforma Evolith — Estándar Raíz (aplica a todos los sistemas hijos: UMS y productos futuros)
Reemplaza: Ninguno
Relacionado: ADR-0052 (Inmutabilidad del Audit Trail), ADR-0056 (Clean Architecture Frontend)


Contexto

Los sistemas distribuidos que abarcan múltiples países y zonas horarias deben manejar fechas, horas y preferencias de idioma de manera consistente en todas las capas. Sin un estándar explícito, los equipos toman decisiones incompatibles: algunos almacenan hora local, otros usan formateo por defecto del browser, otros codifican identificadores de idioma en duro. Cuando los datos cruzan límites de sistemas o se muestran a usuarios en zonas horarias distintas, estas inconsistencias generan errores de visualización, discrepancias en auditorías y fallos de cumplimiento.

Tres preocupaciones independientes deben abordarse juntas porque interactúan en la inicialización de la sesión:

  1. Almacenamiento de fechas y horas: ¿La base de datos almacena UTC u hora local?
  2. Detección de timezone: ¿Cómo sabe el sistema dónde está el usuario y qué zona horaria aplicar al mostrar timestamps?
  3. Resolución de idioma: ¿Qué idioma debe usar la UI y cuál es la cadena de prioridad cuando múltiples fuentes proveen una preferencia?

Todos los sistemas hijos de Evolith (actual: UMS; futuros: facturación, logística, operaciones portuarias, integraciones ERP) deben seguir el mismo estándar para que los trails de auditoría, delegaciones y eventos entre sistemas sean interpretables sin ambigüedad temporal.


Decisiones

D1 — Todas las fechas se almacenan y transmiten en UTC

Regla: Toda fecha o timestamp almacenado en cualquier tabla de base de datos, evento de dominio, mensaje outbox o cuerpo de respuesta API debe ser UTC.

Justificación: UTC es el único ancla sin ambigüedad para sistemas distribuidos. Las horas locales introducen brechas por horario de verano, ambigüedad de reloj de pared e inconsistencia entre datacenters. Almacenar UTC y convertir en el momento de visualización es el estándar de la industria (IANA, RFC 3339, ISO 8601).


D2 — El timezone del browser se detecta al inicio de sesión y se almacena en la sesión

Regla: Al hacer login, el frontend detecta el timezone IANA del browser usando Intl.DateTimeFormat().resolvedOptions().timeZone y lo almacena en el estado de sesión autenticado. Se envía al backend como header X-Timezone en cada llamada API.

Justificación: El browser conoce la zona horaria real del usuario sin requerir configuración manual. El parámetro del tenant cubre casos borde (terminales kiosko, sesiones SSO desde browsers externos) mientras sigue siendo el default sensato para la mayoría de usuarios en la misma región que el tenant.


D3 — La resolución de idioma sigue una cadena de prioridad estricta

Regla: El idioma de la UI se resuelve en la inicialización de la sesión en este orden:

Prioridad Fuente Mecanismo
1 (más alta) Header HTTP Accept-Language del browser Leído por CultureMiddleware del backend, validado contra locales soportados
2 Parámetro de tenant UI_LANGUAGE_DEFAULT Leído desde el caché de configuración en memoria al hacer login
3 (más baja) Default hardcodeado de la plataforma "es" Fallback final

Justificación: La preferencia del browser refleja lo que el usuario configuró a nivel de SO. Respetarla no requiere configuración manual y cubre la mayoría de casos. El admin del tenant puede controlar el fallback para entornos donde la configuración del browser no es representativa (kioscos compartidos, dispositivos gestionados).


Consecuencias

Positivas

Negativas / Trade-offs


Checklist de Implementación (por sistema hijo)


Referencias