From c74843f30c7cace86c700898eee7599f5e81a004 Mon Sep 17 00:00:00 2001 From: JoseSerpaCode <124005402+JoseSerpaCode@users.noreply.github.com> Date: Sun, 18 Oct 2026 14:33:44 -0500 Subject: [PATCH] =?UTF-8?q?fix(deploy):=20el=20servicio=20decide=20=C2=ABh?= =?UTF-8?q?oy=C2=BB=20en=20la=20zona=20de=20Bogot=C3=A1,=20no=20en=20UTC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit `vencida()`, `hoyLocal()` y la foto diaria del burndown usan la zona del proceso, y el unit no fijaba ninguna: en la VM de GCP corría en UTC, así que desde las siete de la tarde en Bogotá el HTML servido marcaba como vencidas las entregas de hoy. El unit fija ahora TZ=America/Bogota, la misma zona de las pruebas e2e. deploy.sh no reinstala el unit, así que el README explica el paso único para una instancia ya desplegada y cómo comprobar que el proceso la tiene. Co-Authored-By: Claude Opus 5.5 --- CHANGELOG.md | 7 +++++++ deploy/README.md | 36 ++++++++++++++++++++++++++++++++++++ deploy/forge-os.service | 8 ++++++++ package-lock.json | 4 ++-- package.json | 2 +- 5 files changed, 54 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index a9f5826..9eb3917 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -6,6 +6,13 @@ El formato está basado en [Keep a Changelog](https://keepachangelog.com/es-ES/1 > Las entradas entre la 0.6.0 y la 1.4.0 se reconstruyeron a posteriori a partir del historial de git, agrupadas por los saltos de versión que realmente ocurrieron en `package.json`. La 1.1.0 nunca existió: se pasó directamente de la 1.0.0 a la 1.2.0. +## [1.28.4] - 2026-10-18 + +### Fixed + +- **En producción, las entregas de hoy salían vencidas por la noche.** La app decide qué día es hoy con la zona del proceso —el rojo de «vencida» en las tarjetas servidas, el contador del Hub, el día de la foto del burndown— y el servicio no fijaba ninguna, así que en la VM corría en UTC: desde las siete de la tarde en Bogotá ya creía que era mañana. El unit de systemd fija ahora `TZ=America/Bogota`, la misma zona con la que corren las pruebas e2e. Las fechas guardadas no cambian. +- Una instancia ya desplegada tiene que copiar el unit una vez, porque `deploy.sh` reinicia el servicio pero no lo reinstala. Los pasos están en `deploy/README.md`, en «La zona horaria». + ## [1.28.1] - 2026-10-18 ### Security diff --git a/deploy/README.md b/deploy/README.md index c0542cb..4d023b0 100644 --- a/deploy/README.md +++ b/deploy/README.md @@ -100,6 +100,39 @@ sudo systemctl enable --now forge-os sudo systemctl status forge-os ``` +### La zona horaria + +El unit fija `TZ=America/Bogota`. No es un detalle de presentación: la app +decide **qué día es hoy** con la zona del proceso, y de eso dependen el rojo de +«vencida» en las tarjetas que pinta el servidor, el contador de vencidas del +Hub y el día con que se guarda la foto diaria del burndown. Una VM de GCP viene +en UTC, así que sin esta línea, desde las siete de la tarde en Bogotá el +servidor ya cree que es mañana y marca como vencida una entrega de hoy. El +navegador lo corrige al repintar, pero el HTML que llega primero está mal. + +Las fechas guardadas **no cambian** con esto: las marcas de +`CURRENT_TIMESTAMP` siguen en UTC y las fechas de entrega son días del +calendario sin zona. Solo cambia qué día se toma como «hoy». + +Si quien usa la instancia vive en otra zona, cambia esa línea del unit, no la +zona de la VM: así no se mueven los logs ni los temporizadores del sistema. + +**Una instancia que ya estaba desplegada no lo recoge sola.** `deploy.sh` +reinicia el servicio pero no vuelve a copiar el unit, así que hay que hacerlo +una vez: + +```sh +sudo cp /opt/forge-os/deploy/forge-os.service /etc/systemd/system/ +sudo systemctl daemon-reload +sudo systemctl restart forge-os +``` + +Y comprobar que el proceso la tiene: + +```sh +sudo cat /proc/$(systemctl show -p MainPID --value forge-os)/environ | tr '\0' '\n' | grep '^TZ=' +``` + ## 5. Caddy **Antes de arrancarlo**, el registro A de `forge-os.online` (en Porkbun) debe @@ -411,6 +444,9 @@ curl -sI https://forge-os.online/_astro/.js | grep -iE 'cache-cont # La API nunca se cachea en capas compartidas curl -sI https://forge-os.online/api/storage/ | grep -i cache-control # private +# El proceso decide «hoy» en la zona de Bogotá, no en UTC +sudo cat /proc/$(systemctl show -p MainPID --value forge-os)/environ | tr '\0' '\n' | grep '^TZ=' + # Sobrevive a un reinicio sudo reboot && sleep 45 && curl -sI https://forge-os.online | head -1 ``` diff --git a/deploy/forge-os.service b/deploy/forge-os.service index 0e1f89b..d2623e4 100644 --- a/deploy/forge-os.service +++ b/deploy/forge-os.service @@ -20,6 +20,14 @@ WorkingDirectory=/opt/forge-os # root: el servicio lo lee al arrancar, el usuario forge no puede leerlo. EnvironmentFile=/etc/forge-os.env +# La zona en la que la app decide qué día es hoy. `vencida()`, `hoyLocal()` y +# la foto diaria del burndown usan la del proceso, y una VM de GCP viene en +# UTC: sin esto, desde las siete de la tarde en Bogotá el servidor ya cree que +# es mañana y pinta como vencida una entrega de hoy. No es un secreto ni cambia +# entre máquinas, por eso va aquí y no en /etc/forge-os.env. Las pruebas e2e +# corren con la misma (`playwright.config.ts`). +Environment=TZ=America/Bogota + ExecStart=/usr/bin/node server.mjs Restart=always diff --git a/package-lock.json b/package-lock.json index 94f2ff5..afc551a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "forge-js", - "version": "1.28.1", + "version": "1.28.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "forge-js", - "version": "1.28.1", + "version": "1.28.4", "dependencies": { "@astrojs/check": "^0.9.10", "@astrojs/node": "^11.1.8", diff --git a/package.json b/package.json index fff6f12..26a2f41 100644 --- a/package.json +++ b/package.json @@ -1,7 +1,7 @@ { "name": "forge-js", "type": "module", - "version": "1.28.1", + "version": "1.28.4", "engines": { "node": ">=22.12.0" },