Pedido de Leo (28-oct, 18:00): Michelle comenta antes de mover y luego tenía que escribir lo mismo otra vez. El «¿por qué?» lista tus últimos comentarios del pendiente; si comentaste después del último cambio de columna, ya viene elegido. PATCH /api/tarea acepta _nota_de (el «cuando» de un comentario tuyo; 400 si no existe o es de otra persona): la entrada guarda «ref», no repite el texto en el hilo y lleva un extracto para la Actividad. En el hilo, el comentario elegido lleva «→ Hecho»; un porqué pegado igual que un comentario anterior también se ve una sola vez. «Comentar» revisa el texto al hacer clic. Pruebas: tests-comentarios.sh (26) y las demás; caso de Michelle en el navegador. DESPLIEGUE A14; lote 2026-10-28_comentarios-elegir. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_013SfRSvDd335NPYEbBrDFGE
44 KiB
Despliegue — sitio, backend de actas y usuarios
Servidor: git.helgen.online · dominio público: https://drogheda.helgen.online
Qué vive dónde
| Parte | Ruta en el servidor | Cómo se actualiza |
|---|---|---|
| Sitio (docs, formularios, tableros) | /srv/projects/drogheda/hbox-docs/site |
./scripts/deploy.sh desde la Mac |
Backend de actas (app.py, tablero.py) |
/srv/projects/drogheda/hbox-docs/backend |
./scripts/deploy.sh lo copia (rsync, sin git en el servidor) + systemctl restart actas-hbox si cambió app.py |
| Actas recibidas (JSON + índice CSV) | /srv/projects/drogheda/actas |
las escribe el backend |
| Fotos de campo | /srv/projects/drogheda/adjuntos |
las escribe el backend |
| Pendientes del tablero (kanban) | /srv/projects/drogheda/tareas |
las escribe el backend — 13-oct |
| Inventario (ítems y movimientos) | /srv/projects/drogheda/inventario |
las escribe el backend — 13-oct |
| Sitios | /srv/projects/drogheda/sitios |
las escribe el backend — 13-oct |
| Plan de producción | /srv/projects/drogheda/plan-produccion.json |
lo escribe el backend (admin) — 13-oct |
| Equipo (miembros, bitácora de accesos) | /srv/projects/drogheda/equipo |
las escribe el backend — 14-oct |
| Enfoque de la semana (página de inicio) | /srv/projects/drogheda/enfoque.json |
lo escriben Leo y Adriana desde el inicio — 21-oct |
| Lotes del tablero ya aplicados | /srv/projects/drogheda/lotes-aplicados.json |
lo escribe backend/tablero.py al aplicar un lote de Claude — 21-oct |
| Foto del tablero (para Claude) | _estado/ en la Mac, fuera de git |
./scripts/tablero.sh foto y cada ./scripts/deploy.sh — 21-oct |
| Usuarios (HTTP Basic) | /etc/nginx/hbox-docs.htpasswd |
htpasswd |
Lo importante: deploy.sh publica el sitio y copia el backend (rsync; en el servidor el
backend no es un repositorio de git), pero no reinicia el servicio. Si cambió backend/app.py, hay
que hacer además el restart, o el sitio nuevo hablará con un backend viejo (las fotos darían 404 y el diagnóstico se bloquearía como si fuera un acta
de banco).
A · Despliegue de esta versión (diagnóstico en campo)
Los pasos 3, 4 y 5 son de una sola vez; los pasos 1 y 2 son el ciclo normal de siempre.
1 · Desde la Mac — publicar el sitio
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
git add -A && git commit -m "diagnóstico en campo: acta, fotos, tablero y procedimiento"
git push
./scripts/deploy.sh # mkdocs build --strict + rsync a /srv/.../site
2 · En el servidor — actualizar el backend
cd /srv/projects/drogheda/hbox-docs && git pull
sudo systemctl restart actas-hbox
curl -s http://127.0.0.1:8081/api/salud # {"ok":true,"servicio":"actas-hbox"}
3 · Carpeta de fotos (una sola vez)
sudo mkdir -p /srv/projects/drogheda/adjuntos
sudo chown -R leo:leo /srv/projects/drogheda/adjuntos
El backend la deduce sola de ACTAS_DIR; si prefieres fijarla, agrega a
/etc/systemd/system/actas-hbox.service (y luego daemon-reload + restart):
Environment=ADJUNTOS_DIR=/srv/projects/drogheda/adjuntos
Environment=ADJUNTO_MAX_MB=8
Environment=ARCHIVO_MAX_MB=20
Environment=ACTAS_REPETIBLES=diagnostico-campo,diagnostico-banco,instalacion-campo,reflasheo,dano,envio,recepcion,prueba-bateria-modem,prueba-ethernet-serie
4 · nginx — subida de fotos e identidad del técnico (una sola vez)
En el bloque server { listen 443 … } de drogheda.helgen.online, el location /api/ queda así:
location /api/ {
proxy_pass http://127.0.0.1:8081;
proxy_set_header Host $host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Remote-User $remote_user; # ← quién es el técnico
client_max_body_size 25m; # ← sin esto, las fotos dan 413
proxy_read_timeout 120s; # ← subidas con señal mala
}
Las dos líneas marcadas son nuevas y obligatorias:
- Sin
client_max_body_size, nginx corta la subida en 1 MB y el técnico ve "la foto pesa demasiado" aunque no lo pese. (El formulario ya reduce cada foto a ~1600 px / 300-400 kB antes de subirla; el margen es para ráfagas de varias fotos.) - Sin
X-Remote-User, el backend no sabe quién envió cada acta: el nombre no se precarga y —más serio— cualquier usuario autenticado podría mandar la cabecera a mano y hacerse pasar porleopara borrar actas. Al fijarla en nginx, el valor del cliente se sobrescribe siempre. Revisa si ya la tienes: es fácil que no, porque no venía en el README original.
sudo nginx -t && sudo systemctl reload nginx
5 · Usuarios de los técnicos (una sola vez)
sudo htpasswd /etc/nginx/hbox-docs.htpasswd alan
sudo htpasswd /etc/nginx/hbox-docs.htpasswd daniel
# (sin -c: -c CREA el archivo de cero y borraría a leo y a luz)
sudo cut -d: -f1 /etc/nginx/hbox-docs.htpasswd # lista de usuarios
Administradores (quién puede borrar o reabrir actas) = variable ACTAS_ADMINS del servicio,
hoy leo. Alan y Daniel quedan como técnicos: llenan y envían, no borran.
7 · Permisos para que los técnicos cambien su contraseña (una sola vez)
La página Mi cuenta (/cuenta.html) deja que cada quien cambie su propia contraseña, y que el
administrador restablezca la de otro. Para eso el servicio tiene que poder escribir el archivo de
usuarios que nginx solo lee:
# quién es el usuario de nginx (normalmente www-data)
grep -E "^\s*user" /etc/nginx/nginx.conf
sudo chown leo:www-data /etc/nginx/hbox-docs.htpasswd
sudo chmod 640 /etc/nginx/hbox-docs.htpasswd
sudo systemctl restart actas-hbox
Así: leo (el servicio) escribe, www-data (nginx) lee, y nadie más puede ni leerlo.
Comprueba que las contraseñas estén en el formato que el servicio sabe verificar:
sudo cut -d: -f2 /etc/nginx/hbox-docs.htpasswd | cut -c1-6
Todas deben decir $apr1$. Si alguna sale distinta ($2y$ es bcrypt), esa persona no va a poder
cambiar la suya sola: restablécesela desde la propia página, que la vuelve a guardar en $apr1$.
!!! note "Por qué no se usa el comando htpasswd desde el servicio"
Pasar una contraseña como argumento (htpasswd -b … clave) la deja visible en ps para
cualquiera con sesión en el servidor. El hash $apr1$ se calcula dentro del proceso; está
verificado carácter por carácter contra la salida de htpasswd, incluyendo acentos y espacios.
!!! tip "Al cambiar la contraseña, la sesión no se cae" HTTP Basic se guarda en el navegador: quien cambie la suya sigue navegando con la anterior hasta que cierre sesión o cierre el navegador. La página lo explica y ofrece la liga de Salir para probarla de inmediato. No es un error.
A2 · Despliegue 13-oct — tableros, inventario, sitios e instalación en campo
Esta versión agrega al backend cuatro colecciones nuevas (pendientes del tablero, plan de
producción, inventario con movimientos, sitios) y páginas que las usan (tableros/, inventario/,
sitios/, formularios/instalacion.html). Igual que siempre: el sitio se publica desde la Mac;
el backend se actualiza en el servidor. Si solo publicas el sitio, los tableros dirán «No se pudo
cargar» porque hablan con endpoints que el backend viejo no tiene.
1 · Desde la Mac — publicar el sitio
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
git add -A && git commit -m "tableros kanban, inventario, sitios, acta de instalación (13-oct)"
git push
./scripts/deploy.sh
2 · En el servidor — backend y carpetas (las carpetas, una sola vez)
ssh leo@git.helgen.online
cd /srv/projects/drogheda/hbox-docs && git pull
# carpetas de las colecciones nuevas (junto a /actas; el backend las deduce de ACTAS_DIR)
sudo mkdir -p /srv/projects/drogheda/{tareas,inventario/items,inventario/movimientos,sitios}
sudo chown -R leo:leo /srv/projects/drogheda/{tareas,inventario,sitios}
sudo chown leo:leo /srv/projects/drogheda # (sin -R) el backend escribe plan-produccion.json en esta carpeta
sudo systemctl restart actas-hbox
curl -s http://127.0.0.1:8081/api/salud # {"ok":true,"servicio":"actas-hbox"}
curl -s -H 'X-Remote-User: leo' http://127.0.0.1:8081/api/tareas/resumen # {"ok":true,"total":0,...}
Variables de entorno: no hace falta tocar el .service. Si quieres mover las carpetas, descomenta
en /etc/systemd/system/actas-hbox.service las líneas TAREAS_DIR, INVENTARIO_DIR, SITIOS_DIR,
PLAN_FILE (vienen comentadas en backend/actas-hbox.service) y luego daemon-reload + restart.
3 · Siembra inicial (una sola vez; repetirla no duplica nada)
cd /srv/projects/drogheda/hbox-docs
./backend/venv/bin/python3 backend/seed_1013.py --usuario leo
Crea: el plan (570 → 113 V5.6 / 327 V5.7 / 130 v6), los 4 sitios (icave, lzc, eit, timsa — ubicación
y contactos «por confirmar» donde no se sabe), 18 ítems de inventario con stock 0 (Jesús hace el
conteo físico con movimientos «ajuste») y los 12 pendientes del tablero del 13-oct. Lo que ya exista
con el mismo id se deja intacto. Para importar los pendientes del Task Tracker de Notion, exporta
una lista JSON con id, titulo, pista, estado, responsable y pásala con --extra archivo.json.
4 · Verificar
curl -s -u leo:PASS https://drogheda.helgen.online/api/tareas | head -c 300
curl -s -u leo:PASS https://drogheda.helgen.online/api/plan | head -c 200
curl -s -u leo:PASS https://drogheda.helgen.online/api/inventario | head -c 200
curl -s -u leo:PASS https://drogheda.helgen.online/api/sitios | head -c 200
Y desde el navegador: /tableros/kanban.html (arrastra un pendiente y revisa que el historial
anote quién lo movió), /inventario/inventario.html (registra un «ajuste» con el conteo real),
/sitios/sitio.html?id=icave, /formularios/instalacion.html con la unidad PRUEBA.
5 · Respaldo
Se suman tres carpetas y un archivo a la rutina de siempre:
rsync -az leo@git.helgen.online:/srv/projects/drogheda/tareas/ ~/respaldo-tareas/
rsync -az leo@git.helgen.online:/srv/projects/drogheda/inventario/ ~/respaldo-inventario/
rsync -az leo@git.helgen.online:/srv/projects/drogheda/sitios/ ~/respaldo-sitios/
rsync -az leo@git.helgen.online:/srv/projects/drogheda/plan-produccion.json ~/respaldo-plan/
A3 · 14-oct: equipo y usuarios
Agrega la colección equipo (quién es quién; los responsables de los pendientes), la administración
de accesos desde el sitio (/tableros/equipo.html, solo admin) y hace obligatorio el responsable en
cada pendiente. Compatible con lo ya desplegado: los pendientes viejos siguen funcionando; la siembra
les calcula responsable_ids y pone leo solo donde el responsable estaba vacío.
# Mac
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs && git add -A && git commit -m "equipo, usuarios y responsables (14-oct)" && git push && ./scripts/deploy.sh
# servidor
ssh leo@git.helgen.online
cd /srv/projects/drogheda/hbox-docs && git pull
sudo systemctl restart actas-hbox
./backend/venv/bin/python3 backend/seed_1013.py --usuario leo # crea equipo/ (9 miembros, sin accesos) + el pendiente de ferretería; no duplica
curl -s -H 'X-Remote-User: leo' http://127.0.0.1:8081/api/equipo | head -c 200
La carpeta equipo/ la crea la siembra (o el backend al primer alta) junto a /actas; no hay
variables nuevas que fijar (EQUIPO_DIR, HTPASSWD_LOCK vienen comentadas en el .service).
Para crear o quitar accesos desde la página, el servicio tiene que poder escribir el htpasswd —
es lo mismo que ya pide «Mi cuenta» (§7): sudo chown leo:www-data /etc/nginx/hbox-docs.htpasswd && sudo chmod 640 /etc/nginx/hbox-docs.htpasswd. Si no está hecho, la página de Equipo lo avisa y solo
deja editar miembros. A partir de aquí los usuarios se crean en Equipo → Nuevo usuario / miembro
(la contraseña inicial se muestra una sola vez), no con htpasswd en el servidor. Las cuentas que ya
existen y no son miembro (p. ej. luz) aparecen como «cuentas con acceso que no están en el equipo»:
dales de alta como miembro sin marcar «crear acceso».
Verificar: /tableros/equipo.html como leo (botones) y como un técnico (solo lectura); crear un
pendiente sin responsable debe rechazarse; backend/tests-1014.sh reproduce todo con un htpasswd temporal.
| Síntoma | Causa | Arreglo |
|---|---|---|
| Los tableros dicen «No se pudo cargar (HTTP 404)» | backend viejo | paso 2 (git pull + restart) |
| «El servicio no tiene permiso de escribir el archivo de usuarios» al crear un acceso | falta el chown/chmod del htpasswd |
§7 |
| «Falta el responsable del pendiente» al crear | regla del 14-oct | elige a alguien del equipo (o escríbelo en texto libre) |
| «No puedo identificarte (falta X-Remote-User…)» al crear o mover | nginx no manda la cabecera | paso 4 del despliegue anterior |
| El tablero sale vacío | falta la siembra | paso 3 |
| «Solo un administrador…» al borrar o editar sitios/plan | ese usuario no está en ACTAS_ADMINS |
así debe ser; pide a Leo |
PermissionError al guardar el plan |
/srv/projects/drogheda no es de leo |
chown del paso 2 |
A4 · 21-oct: página de inicio, enfoque de la semana y actividad
El inicio deja de ser una página escrita a mano: lee docs/datos/proyecto.json (fase, ruta a
producción, fechas, sitios), el tablero y dos rutas nuevas del backend:
GET /api/hoy·PUT /api/hoy: el enfoque de la semana. Lo escribenHOY_EDITORES(por omisiónleo,adriana) y los administradores; se guarda enenfoque.jsonjunto a/actas, con sus 20 versiones anteriores.GET /api/actividad?dias=7&limite=30: lo que pasó, del historial de los pendientes y de las actas recibidas (sin las series PRUEBA). La usan el inicio y la Bitácora.
No hay carpetas ni variables nuevas que fijar (las dos vienen comentadas en el .service). Como
cambió backend/app.py, después del deploy hay que reiniciar el servicio:
# Mac
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs && ./scripts/deploy.sh
ssh leo@git.helgen.online 'sudo systemctl restart actas-hbox'
# verificar (en el servidor)
curl -s -H 'X-Remote-User: leo' http://127.0.0.1:8081/api/hoy
curl -s -H 'X-Remote-User: leo' 'http://127.0.0.1:8081/api/actividad?dias=7&limite=3' | head -c 400
| Síntoma | Causa | Arreglo |
|---|---|---|
| En el inicio, el enfoque dice «El servidor no respondió» y la actividad, «HTTP 404» | backend viejo | el restart de arriba |
| «El enfoque de la semana lo escriben adriana y leo» al guardar | ese usuario no está en HOY_EDITORES |
así debe ser; para agregar a alguien, Environment=HOY_EDITORES=leo,adriana,… en el .service |
PermissionError al guardar el enfoque |
/srv/projects/drogheda no es de leo |
chown del paso 2 de A2 |
A5 · 21-oct: el sitio como centro de mando — lotes y foto del tablero
Regla de Leo (21-oct): si no está en el sitio, no pasó; cada tarea termina aquí. Claude no llega al
servidor, así que deja sus cambios al tablero en lotes (backend/lotes/AAAA-MM-DD_tema.json, uno por
tarea terminada) y lee el tablero en una foto (_estado/tablero.md, en la Mac). backend/tablero.py
hace las dos cosas en el servidor a través del mismo backend (127.0.0.1:8081): cada cambio pasa por
las mismas validaciones que el sitio y queda en el historial con su autor (claude) y su nota. No
cambia app.py ni pide reiniciar nada. Formato y reglas: backend/lotes/README.md.
# Mac — deploy.sh ya copia tablero.py y al final baja la foto
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
./scripts/deploy.sh # termina con «Foto del tablero en _estado/tablero.md» y «Tablero: N cambio(s)…»
./scripts/tablero.sh revisar # qué haría el lote 2026-10-21_pasada-6 contra el tablero real
./scripts/tablero.sh aplicar # lo aplica y baja la foto nueva
El primer lote (2026-10-21_pasada-6, cierre de la pasada 6) cierra lo que la pasada terminó
(pasadas 2 a 5 y la fuente de la V5.7), pone en curso la revisión y el Gerber del piloto, crea D-21-2
para Leo, el pedido del piloto (si no existe ya uno), la prueba de banco de la V5.7 (si no existe) y el
pendiente de D34 de la v6 para Michelle, y comenta los de la v6. Lo que no cuadra con el tablero real
(ya está en Hecho, no existe, hay uno parecido, el título coincide con varios) se salta, y revisar
dice por qué antes de escribir nada.
| Síntoma | Causa | Arreglo |
|---|---|---|
No contesta el backend en http://127.0.0.1:8081 |
el servicio está abajo | ssh leo@git.helgen.online 'sudo systemctl status actas-hbox' |
…/venv/bin/python3: No such file or directory |
el venv vive en otro lugar | BACKEND_PATH=/ruta/al/backend ./scripts/tablero.sh … |
PermissionError en lotes-aplicados.json |
/srv/projects/drogheda no es de leo |
chown del paso 2 de A2 |
| «los cambios N ya no son los que se aplicaron» | alguien editó un lote ya aplicado | un lote aplicado no se edita: Claude escribe otro |
| un cambio «se salta» y no debía | el título del pendiente real es distinto | pásale a Claude la línea de revisar; escribe un lote nuevo con el id correcto |
A6 · 22-oct: modo crisis — semáforo, sitio de cada pendiente y juntas
Qué cambia: la página de inicio muestra el semáforo del proyecto (rojo) y el color de cada sitio (docs/datos/proyecto.json);
cada pendiente lleva su sitio (sitios: icave, timsa, eit, lzc, qro; sin sitio = Querétaro), con filtro y vista Por sitio
en Pendientes; pista nueva Gestión; página nueva Juntas. backend/tablero.py acepta sitios en los lotes, salta un lote
con errores sin frenar los demás y recorta notas de más de 300 caracteres (lo avisa).
Cambió backend/app.py: hay que reiniciar el servicio ANTES de aplicar lotes con sitios. Con el backend viejo, revisar
marca esos cambios como inválidos («el backend todavía no conoce «sitios»: reinicia actas-hbox») y no los manda.
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
mkdocs build --strict
git add -A && git commit -m "Modo crisis: semáforo, sitio por pendiente, juntas" && git push
cd .. && git add hbox-docs && git commit -m "hbox-docs: modo crisis" && git push && cd hbox-docs # sube el submódulo
./scripts/deploy.sh # sitio + backend (rsync); la foto todavía con el backend viejo
ssh leo@git.helgen.online 'sudo systemctl restart actas-hbox'
curl -s -u leo:PASS 'https://drogheda.helgen.online/api/tareas?sitio=eit' | head -c 300 # «sitios» en la respuesta
./scripts/tablero.sh revisar # ya con sitios
./scripts/tablero.sh aplicar
| Síntoma | Causa | Arreglo |
|---|---|---|
| En Pendientes no aparecen los botones de sitio | navegador con el kanban.js viejo |
recarga (los .js llevan ?v= desde el 21-oct) |
Sitio inválido: … al guardar |
sitio que no existe | icave, timsa, eit, lzc o qro (también acepta Veracruz, Manzanillo, Ensenada, LCT, Querétaro) |
revisar dice «el backend todavía no conoce «sitios»» |
no se reinició el servicio | el restart de arriba |
A7 · 22-oct: tablero de Instalaciones por sitio y prueba en sitio
Qué cambia: página nueva Instalaciones (/tableros/instalaciones/, pestañas ICAVE · TIMSA · EIT · LCT): una tarjeta por
unidad con su vehículo, sus actas y su etapa (enviada → recibida → instalada → probada en sitio → en operación, más «con
falla») contra la meta de cada sitio. Acta nueva Prueba en sitio (formularios/prueba-sitio.html, tipo prueba-sitio).
El acta de instalación pide además 12/24 V, los tipos Reach Stacker y Empty Handler y el nombre en el monitor (H00xx). Los
formularios aceptan ?serie=…&sitio=… para abrir la siguiente acta ya llena (acta.js).
Backend: backend/instalaciones.py (nuevo; lo engancha el final de app.py) da GET /api/instalaciones[?sitio=eit] y vuelve
repetible prueba-sitio sin tocar ACTAS_REPETIBLES del servicio. deploy.sh ya copia el archivo nuevo.
Cambió backend/app.py: reinicia el servicio. Sin reiniciar, la página dice «falta reiniciar el servicio actas-hbox» y
la segunda prueba en sitio de una misma unidad daría «Ya existe un acta».
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
mkdocs build --strict
git add -A && git commit -m "Tablero de Instalaciones por sitio y acta de prueba en sitio" && git push
cd .. && git add hbox-docs && git commit -m "hbox-docs: tablero de Instalaciones" && git push && cd hbox-docs # sube el submódulo
./scripts/deploy.sh # sitio + backend (rsync, ya con instalaciones.py)
ssh leo@git.helgen.online 'sudo systemctl restart actas-hbox'
curl -s -u leo:PASS 'https://drogheda.helgen.online/api/instalaciones?sitio=icave' | head -c 300 # «"ok": true»
| Síntoma | Causa | Arreglo |
|---|---|---|
| «No se pudo leer el tablero de instalaciones (HTTP 404)» | servicio sin reiniciar, o falta backend/instalaciones.py en el servidor |
deploy.sh y el restart; si falta el archivo, journalctl -u actas-hbox dice «instalaciones.py no se cargó» |
| Una unidad instalada no aparece | no tiene acta, o su acta no trae el sitio ni el nombre del puerto | llenar el acta de instalación con el sitio y la fecha real |
| La unidad sale en otro sitio | cuenta en el sitio de su acta más reciente | revisar el sitio de esa acta en el expediente |
A8 · 22-oct: Adriana y Gibran pueden borrar pendientes
Qué cambia: borrar un pendiente ya no es solo de los administradores (ACTAS_ADMINS): también pueden los usuarios de
TAREAS_BORRAN, que por omisión son adriana y gibranlp (no hace falta tocar el servicio). No cambia ningún otro
permiso: actas, usuarios, sitios y plan siguen siendo solo de administradores.
Borrar ya no destruye: el pendiente pasa a /srv/projects/drogheda/tareas/_borrados/<id>__<AAAAMMDDhhmmss>.json con su
historial, sigue en la Actividad («Adriana borró …», sin liga) y quien lo esperaba («Espera a que terminen») deja de
esperarlo, con una nota en su historial.
Cambió backend/app.py: reinicia el servicio.
./scripts/deploy.sh
ssh leo@git.helgen.online 'sudo systemctl restart actas-hbox'
Para dar o quitar el permiso: en /etc/systemd/system/actas-hbox.service, la línea
Environment=TAREAS_BORRAN=adriana,gibranlp con los usuarios que sí (los administradores siempre pueden); después
sudo systemctl daemon-reload && sudo systemctl restart actas-hbox.
Recuperar un pendiente borrado (en el servidor):
cd /srv/projects/drogheda/tareas
ls _borrados/ # <id>__AAAAMMDDhhmmss.json
mv _borrados/<id>__<fecha>.json <id>.json # vuelve al tablero como estaba; las dependencias que se quitaron no regresan solas
| Síntoma | Causa | Arreglo |
|---|---|---|
| Adriana o Gibran no ven «Borrar» en el detalle | servicio sin reiniciar | el restart de arriba |
| «Solo … pueden borrar pendientes» | ese usuario no es administrador ni está en TAREAS_BORRAN |
así debe ser; si debe poder, agrégalo a TAREAS_BORRAN |
A9 · 23-oct: inventario por sitio
Qué cambia: Inventario (/tableros/inventario/) tiene una pestaña por sitio —ICAVE · TIMSA · EIT · LCT · Querétaro— y
Todo. Cada movimiento dice en qué sitio pasó. Tipo nuevo Envío: saca material de un sitio (o de «Proveedor o fuera
del inventario»: una compra en camino, o material que salió antes de que se contara) y lo deja en camino hasta que el
sitio que lo espera le da Recibir (tipo recepcion; si llegó menos, la diferencia baja del total). Cada ítem puede decir
cuánto lleva una instalación (Por instalación) y la pestaña de cada puerto calcula qué falta para instalar N unidades.
Categoría nueva Instalación (soportes, tornillería, cable de potencia). Instalaciones tiene un botón Material que abre
la pestaña del sitio. El CSV trae una columna por sitio y otra de lo que va en camino. Reglas para el equipo:
Política de inventario.
Datos: no hay migración. Los movimientos de antes no tienen sitio y cuentan como Querétaro; el total de cada ítem no
cambia. El primer paso del equipo es el conteo físico de cada sitio (lote 2026-10-23_inventario-sitios).
Cambió backend/app.py: reinicia el servicio. Sin reiniciar, la página muestra solo Todo y avisa que falta
reiniciar actas-hbox.
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
mkdocs build --strict
git add -A && git commit -m "Inventario por sitio: pestañas, envíos en camino y kit por instalación" && git push
cd .. && git add hbox-docs && git commit -m "hbox-docs: inventario por sitio" && git push && cd hbox-docs # sube el submódulo
./scripts/deploy.sh
ssh leo@git.helgen.online 'sudo systemctl restart actas-hbox'
curl -s -u leo:PASS https://drogheda.helgen.online/api/inventario | head -c 300 # debe traer «"sitios"» y «"envios"»
./scripts/tablero.sh revisar && ./scripts/tablero.sh aplicar
Pruebas en la Mac (opcional, necesita Flask): bash backend/tests-1023.sh . (35 revisiones: entrada por sitio, envío,
recepción completa y con faltante, conteo físico, envío desde fuera, errores y CSV).
| Síntoma | Causa | Arreglo |
|---|---|---|
| Solo se ve Todo y un aviso de reiniciar | servicio sin reiniciar | el restart de arriba |
| «No hay stock suficiente en EIT: hay 0 pza registrados» | ese sitio no tiene su conteo físico ni entradas | Conteo físico en ese sitio primero; si es material que ya salió sin contarse, envío desde «Proveedor o fuera del inventario» |
| Un envío no sale en la pestaña del sitio que lo espera | se registró con otro destino, o ya se recibió | tocar el código del ítem: sus movimientos dicen a dónde iba y quién lo recibió |
| El total de un ítem subió sin que llegara nada | un envío desde «Proveedor o fuera del inventario» entra al total al registrarse (va en camino) | así debe ser; si al recibir llega menos, la diferencia baja |
A10 · 23-oct: cuentas nuevas, contraseña inicial para todos y correo de cada quien
Qué cambia:
backend/cuentas.py(nuevo;deploy.shya lo copia junto conbackend/cuentas/): restablece contraseñas en bloque y da de alta a varios. Primera corrida (cuentas/2026-10-23_alta-sitios.json): altas de jesush (Jesús Honorato, TIMSA), miguel (Miguel Ángel Peña, EIT), joel (Joel Orantes, EIT), antonio (Antonio Ventura, LCT) y danielg (Daniel González Cruz, ensamble, Querétaro); el usuariojesuspasa a llamarse Jesús Romero; se llenan los correos que ya conocíamos; y todos menos leo y claude quedan con la misma contraseña inicial.- Equipo: columnas Sitio y Correo, filtro por sitio, campos «Sitio» y «Otro correo» (el del otro dominio) y, para el administrador, la marca contraseña inicial.
- Quien sigue con la contraseña inicial ve una franja arriba en todas las páginas, con la liga a Mi cuenta; se quita sola cuando la cambia.
- Los pendientes que tenían a alguien como texto libre («Miguel») ya cuentan como suyos en cuanto se da de alta.
Cambió backend/app.py: reinicia el servicio antes de correr cuentas.py y antes de aplicar el lote.
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
mkdocs build --strict
git add -A && git commit -m "Cuentas en bloque, contraseña inicial y sitio/correo en Equipo" && git push
cd .. && git add hbox-docs CLAUDE.md && git commit -m "hbox-docs: cuentas del 23-oct" && git push && cd hbox-docs
./scripts/deploy.sh
ssh leo@git.helgen.online 'sudo systemctl restart actas-hbox'
ssh -t leo@git.helgen.online 'cd /srv/projects/drogheda/hbox-docs/backend && venv/bin/python3 cuentas.py todo cuentas/2026-10-23_alta-sitios.json'
./scripts/tablero.sh revisar && ./scripts/tablero.sh aplicar # lote 2026-10-23_usuarios-campo
cuentas.py muestra el plan (altas, a quién restablece, qué datos llena) y pide «si»; luego la contraseña, dos veces y
sin eco. No la escribas en ningún archivo ni en un chat de grupo: pásala en persona o por mensaje directo. Para revisar
después (sin contraseñas ni hashes):
ssh leo@git.helgen.online 'cd /srv/projects/drogheda/hbox-docs/backend && venv/bin/python3 cuentas.py lista'.
Pruebas en la Mac (opcional, necesita Flask): bash backend/tests-cuentas.sh . (47 revisiones).
| Síntoma | Causa | Arreglo |
|---|---|---|
cuentas.py: «No encuentro el archivo de usuarios» o PermissionError |
no se corrió como leo, o el htpasswd no es de leo |
correr como leo; sudo chown leo:www-data /etc/nginx/hbox-docs.htpasswd && sudo chmod 640 /etc/nginx/hbox-docs.htpasswd |
| Alguien no puede entrar después | escribió otra contraseña, o su cuenta salió como «sin miembro activo» y no se tocó | cuentas.py lista; restablécesela en Mi cuenta (admin) |
| Hay que deshacer el restablecimiento | — | el archivo anterior quedó en /srv/projects/drogheda/equipo/_respaldos/htpasswd-AAAAMMDD-hhmmss: cópialo encima de /etc/nginx/hbox-docs.htpasswd como leo |
| No sale la franja de la contraseña ni la columna Sitio | servicio sin reiniciar | el restart de arriba |
A11 · 27-oct: página de entrada, incidencias, standup, vigía y agente diario
Por qué. Adriana reportó el 26-oct que, después de restablecer contraseñas, la gente no podía volver a entrar. Con la
ventana gris de HTTP Basic el navegador y el teléfono guardan la contraseña anterior y la vuelven a mandar sola; Mi cuenta
no tenía campo de usuario (el gestor de contraseñas nunca se actualizaba); «Adriana» con mayúscula no existe para nginx; no
había cómo cerrar sesión ni registro de quién fallaba. Además, a las 9:15 del 27-oct se instaló a mano un
actas-hbox.service viejo (sin prueba-ethernet-serie) que el repo no tenía.
Qué cambia.
- Página de entrada propia (
docs/entrar.html,backend/acceso.py): nginx pregunta a/api/_authen cada petición (auth_request); sesión = cookie firmada de 30 días; se entra con el usuario o con el correo de Equipo, sin importar mayúsculas ni espacios; cambiar la propia contraseña no saca a nadie; restablecer cierra las sesiones de esa persona; cada intento queda en/srv/projects/drogheda/acceso/intentos-AAAA-MM.jsonl(sin la contraseña) y se ve en Incidencias (administradores). Las contraseñas siguen en el mismo htpasswd: Mi cuenta, Equipo ycuentas.pyno cambian.curl -uya no entra (revisión de seguridad: por ahí se podían probar contraseñas sin límite). Los scripts del servidor (vigía,tablero.py, el agente) hablan con127.0.0.1:8081directo; para probar desde tu terminal:read -s P; curl -c /tmp/j -H 'Content-Type: application/json' -d "{\"usuario\":\"leo\",\"password\":\"$P\"}" https://drogheda.helgen.online/api/entrar && curl -b /tmp/j https://drogheda.helgen.online/api/whoami. Revisión de seguridad independiente antes de publicar (27-oct): además, POST/PATCH/DELETE solo desde páginas del sitio, bloqueo por usuario + IP (nadie deja fuera a otro), redirección después de entrar solo dentro del sitio, avisos públicos solo con su texto público, y lo tecleado como usuario se guarda enmascarado. - nginx (
backend/nginx/drogheda.helgen.online.conf, lo instalabackend/nginx/cambiar-entrada.shcon respaldo,nginx -t, 14 pruebas —incluida una sesión de prueba firmada con el secreto del servicio, sin contraseña— y regreso automático; revisa antes que todas las contraseñas sean$apr1$): sin sesión →/entrar.html; las API → 401 JSON; públicos solo la entrada,/publico/, las fuentes,helgen.css,tema.jsy el ícono;X-Remote-Userlo pone nginx desde la sesión. - Servicio (
backend/actas-hbox.service):ACTAS_ADMINS=leo,gibranlp(como lo dejó Gibran), la lista completa de actas repetibles, gunicorn con hilos (-k gthread -w 2 --threads 8: cada página pasa por/api/_auth) yRestart=always. - Incidencias (
backend/incidencias.py,docs/js/incidencias.js,docs/tableros/incidencias.md): «Problemas del sitio» al pie de cada página, reporte sin sesión desde la entrada, avisos públicos, errores del navegador y del servidor en/srv/projects/drogheda/incidencias/_errores/. - Standup (
backend/standup.py,docs/tableros/standup.md,docs/js/standup.js) y vigía (backend/vigia.py, crontab de leo, minuto 7 de cada hora). Reglas:docs/agentes.md; instrucciones del agente:agentes/agente-diario.md. - Correos de Equipo:
backend/cuentas/2026-10-27_correos.json(12 correos; solo llena vacíos).
Un comando (en la Mac; pide sudo una vez y dos «si»):
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs && ./scripts/despliegue-1027.sh
Lo mismo a mano: sync-docs.sh → commit/push de hbox-docs y del submódulo → ./scripts/deploy.sh →
ssh -t leo@git.helgen.online 'sudo bash /srv/projects/drogheda/hbox-docs/backend/nginx/cambiar-entrada.sh servicio && sudo bash /srv/projects/drogheda/hbox-docs/backend/nginx/cambiar-entrada.sh aplicar'
→ cuentas.py alta cuentas/2026-10-27_correos.json → crontab del vigía + semilla_1027.py → tablero.sh revisar / aplicar.
Regresar a la ventana gris (si algo no te gusta; el servicio nuevo puede quedarse):
ssh -t leo@git.helgen.online 'sudo bash /srv/projects/drogheda/hbox-docs/backend/nginx/cambiar-entrada.sh deshacer'.
Confirmar la causa del 26-oct (opcional, lee el log de nginx de antes del cambio):
ssh -t leo@git.helgen.online "sudo grep -hE 'password mismatch|was not found' /var/log/nginx/error.log /var/log/nginx/error.log.1 | tail -40"
— «password mismatch» = contraseña vieja o mal escrita; «was not found» = usuario mal escrito (p. ej. con mayúscula).
| Síntoma | Causa | Arreglo |
|---|---|---|
| Sale «Un momento…» en todas las páginas | el backend no contesta (sin él no hay sesión) | ssh -t leo@git.helgen.online 'sudo systemctl status actas-hbox'; journalctl -u actas-hbox -n 50 |
| La entrada dice «No encuentro ese usuario» | escribió otro usuario; el registro de intentos lo dice | Incidencias → «Intentos de entrada»; su usuario está en Equipo |
| Alguien entra pero las API dicen 401 | cookie de otro dominio o navegador sin cookies | que entre de nuevo en /entrar.html; si sigue, incidencia con datos técnicos |
cambiar-entrada.sh aplicar dice que el backend no tiene la entrada |
falta el paso servicio (reiniciar con los módulos nuevos) |
correr servicio primero |
| Quiero cerrar la sesión de todos | — | sudo rm /srv/projects/drogheda/.sesion-secreto && sudo systemctl restart actas-hbox |
A12 · 28-oct: fotos de la galería y documentos en las actas
Lo pidió el equipo de campo (Leo, 28-oct 12:10): en los formularios solo se podía tomar la foto en vivo, no elegirla de la galería, y no había dónde subir un documento terminado.
docs/formularios/acta.js+acta.css: cada foto tiene dos botones, Tomar foto (cámara) y Elegir de la galería (sincapture); una foto HEIC que el navegador no puede convertir lo dice en vez de fallar en el servidor. Sección Documentos al final de toda acta (opcional;cfg.sinDocumentosla quita): PDF, Word, Excel, ODT/ODS, PowerPoint o la foto de una hoja. Los botones de subir se desactivan en un acta ya enviada.backend/app.py:/api/archivosacepta ademásEXT_DOC(.pdf .docx .xlsx .pptx .odt .ods .doc .xls .ppt) y revisa los primeros bytes (un HTML renombrado a .pdf se rechaza)./api/adjuntomandanosniff, abre en el navegador fotos, PDF y texto, y descarga lo demás con su nombre original.docs/tableros/unidad.md: el expediente dice «Archivos y documentos».- Pruebas:
bash backend/tests-actas-documentos.sh .(15; se llamaba tests-1028.sh, nombre que pasó a Compras) además de 1027 (55), 1023 (35) y campeón (25); en teléfono, claro y oscuro.
Ya está desplegado (28-oct, 12:17): páginas con rsync después de la comparación con el servidor, y el backend con
kill -HUP al proceso maestro de gunicorn (corre como leo: recarga los workers sin sudo y sin cortar). Si algo
falla: git revert del commit y ./scripts/deploy.sh, luego ssh -t leo@git.helgen.online 'sudo systemctl restart actas-hbox'.
A13 · 28-oct: comentarios en los pendientes y «¿por qué?» al moverlos
Lo pidió Leo (28-oct, 12:57 y 16:12): que cada tarjeta tenga comentarios y que se pueda justificar por qué se movió, sobre todo cuando algo pasó a Hecho sin estar terminado.
backend/app.py(PATCH/api/tarea):_notahasta 1000 caracteres (antes 300) y además del texto del historial queda aparte enhistorial[-1].nota. Comentar no necesita ser campeón; mover sí (sin cambio).docs/tableros/kanban.js+tablero.css: sección Comentarios en el detalle (hilo + caja) y contador en la tarjeta;reglaMover()pide «¿por qué?» en el mismo PATCH: a Hecho (evidencia, D-27-6), al reabrir desde Hecho, a Bloqueado y de En curso a Por hacer; «Cancelar» o Esc lo deja donde estaba. Lo demás se mueve sin preguntar. Vale para arrastrar, la franja, las flechas, «Mover a…» y los botones del detalle. En el teléfono el detalle cabe en la pantalla.docs/tableros/pendientes.md(«Cómo se usa») yjuntas.md(D-27-6) lo explican.- Pruebas:
bash backend/tests-comentarios.sh .(16) además de 1027 (55), 1028 Compras (58), 1023 (35), campeón (25) y actas-documentos (15); en el navegador: escritorio y teléfono (iPhone 13 y SE), claro y oscuro.
Desplegado el 28-oct: páginas con rsync después de la comparación con el servidor, backend con kill -HUP al maestro de
gunicorn. Para deshacer: git revert del commit, ./scripts/deploy.sh y ssh -t leo@git.helgen.online 'sudo systemctl restart actas-hbox'.
A14 · 28-oct: elegir uno de tus comentarios como el porqué
Lo pidió Leo (28-oct, 18:00): Michelle comenta antes de mover y luego el «¿por qué?» la hacía escribir lo mismo otra vez.
backend/app.py(PATCH/api/tarea):_nota_de= elcuandode un comentario de la misma persona en ese pendiente (si no existe o es de otra persona: 400). La entrada del movimiento guardaref(sinnota, así no se repite) y su texto para la Actividad lleva «por su comentario del dd/mm hh:mm: «extracto»». Con_notaademás, guarda las dos cosas.docs/tableros/kanban.js+tablero.css: el «¿por qué?» lista tus últimos 5 comentarios del pendiente; si comentaste después del último cambio de columna, ese ya viene elegido (un clic en «Mover»). «Escribir otro motivo» sigue ahí. En el hilo, el comentario elegido lleva la etiqueta «→ Hecho». El porqué pegado igual que un comentario anterior de la misma persona también se muestra una sola vez. El orden se toma del historial, no de la hora (hay horas en UTC y en hora local).- Pruebas:
bash backend/tests-comentarios.sh .(26) y las demás; en el navegador, el caso de Michelle de punta a punta.
Desplegado igual que A13 (rsync de páginas tras la comparación; kill -HUP al maestro de gunicorn).
B · Verificación después de desplegar
# 1. el backend responde y sabe quién eres
curl -s -H 'X-Remote-User: leo' http://127.0.0.1:8081/api/whoami # en el servidor (desde el 27-oct curl -u ya no entra por fuera)
curl -s -H 'X-Remote-User: alan' http://127.0.0.1:8081/api/whoami # {"user":"alan","admin":false}
Si user sale vacío, falta la línea X-Remote-User del paso 4.
# 2. la subida de fotos funciona de punta a punta
curl -s -u alan:PASS -F tipo=diagnostico-campo -F serie=CAMPO-PRUEBA \
-F foto=@cualquier-foto.jpg \
https://drogheda.helgen.online/api/adjuntos
# → {"ok":true,"fotos":[{"ruta":"diagnostico-campo/CAMPO-PRUEBA/2026…jpg",…}]}
# 3. el acta de campo NO se bloquea al segundo envío
curl -s -u alan:PASS https://drogheda.helgen.online/api/historial\?tipo=diagnostico-campo\&serie=CAMPO-PRUEBA
Y la prueba que de verdad cuenta, desde un teléfono:
abrir https://drogheda.helgen.online/formularios/diagnostico.html, elegir la unidad
⚙ PRUEBA (no cuenta), tomar una foto y enviar. Las series con PRUEBA se guardan aparte,
en _pruebas/, y no ensucian el registro.
C · Ciclo normal a partir de aquí
# contenido nuevo desde el repo Drogheda (lista curada dentro del script)
./scripts/sync-docs.sh
git add -A && git commit -m "…" && git push
./scripts/deploy.sh # sitio + backend (rsync) + foto del tablero
./scripts/tablero.sh revisar # si Claude dejó un lote nuevo en backend/lotes/
./scripts/tablero.sh aplicar
# y SOLO si cambió backend/app.py (deploy.sh ya lo copió):
ssh leo@git.helgen.online 'sudo systemctl restart actas-hbox'
D · Respaldo
Todo lo que los técnicos generan son dos carpetas planas — cópialas y ya:
rsync -az leo@git.helgen.online:/srv/projects/drogheda/actas/ ~/respaldo-actas/
rsync -az leo@git.helgen.online:/srv/projects/drogheda/adjuntos/ ~/respaldo-fotos/
D4 · 28-oct: Compras (órdenes de compra del cotizador) y la hora local
backend/app.py cambió (engancha compras.py) y el servicio también, así que hay que reiniciar.
cd ~/Documents/Claude/Projects/Drogheda/hbox-docs
./scripts/deploy.sh # sube el sitio y backend/compras.py; revisa enlaces antes de publicar
ssh leo@git.helgen.online
sudo cp /srv/projects/drogheda/hbox-docs/backend/actas-hbox.service /etc/systemd/system/
sudo systemctl daemon-reload && sudo systemctl restart actas-hbox
curl -s localhost:8081/api/compras -H 'X-Remote-User: leo' | head -c 200 # debe traer ok:true
Qué trae el servicio nuevo:
TZ=America/Mexico_City— el servidor corre en UTC y por eso el sitio enseñaba todo 6 horas adelantado (lo vio el equipo en la junta del 28-oct). Desde el reinicio, cada fecha que escribe el backend queda en hora de Querétaro. Lo guardado antes del 28-oct sigue en UTC y no se corrige solo.COTIZADOR_SECRETO(comentado) — el secreto compartido con el cotizador. Mientras no esté, las rutas/api/integracion/contestan 503 con un mensaje claro, la página Compras lo avisa y el resto del sitio funciona igual. Para encenderlo:
openssl rand -hex 32 # el MISMO valor va en el cotizador como PORTAL_SECRETO
sudo systemctl edit actas-hbox # o descomenta la línea en el .service y vuelve a copiarlo
La base /srv/projects/drogheda/drogheda.db se crea sola al arrancar (SQLite en modo WAL) y se respalda con el
resto de /srv/projects/drogheda. nginx no necesita cambios: /api/integracion/ entra por el location /api/
que ya existe y la firma la revisa el backend, no la sesión.
Pruebas antes de publicar: bash backend/tests-1028.sh ~/Documents/Claude/Projects/Drogheda/hbox-docs (58).
E · Problemas frecuentes
| Síntoma | Causa | Arreglo |
|---|---|---|
| "La foto pesa demasiado" con fotos normales | falta client_max_body_size |
paso 4 |
| El nombre del técnico no se precarga | falta X-Remote-User |
paso 4 |
| "Ya existe un acta para esta serie" en diagnóstico | backend viejo | paso 2 (git pull + restart) |
| Las fotos se ven rotas en el tablero | falta la carpeta adjuntos o su permiso |
paso 3 |
mkdocs build --strict falla |
un enlace del nav apunta a un archivo que no existe |
revisa mkdocs.yml |
| El técnico no puede entrar | usuario no creado, o se usó htpasswd -c y borró a los demás |
paso 5 |
| «El servicio no tiene permiso de escribir el archivo de usuarios» | falta el chown/chmod del htpasswd |
paso 7 |
| «Tu contraseña está guardada en un formato que no puedo verificar» | esa entrada es bcrypt, no $apr1$ |
restablecerla desde /cuenta.html como administrador |