# 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 ```bash 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 ```bash 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) ```bash 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`): ```ini 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í: ```nginx 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 por `leo` para 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. ```bash sudo nginx -t && sudo systemctl reload nginx ``` ### 5 · Usuarios de los técnicos (una sola vez) ```bash 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**: ```bash # 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: ```bash 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 ```bash 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) ```bash 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) ```bash 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 ```bash 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: ```bash 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. ```bash # 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 escriben `HOY_EDITORES` (por omisión `leo,adriana`) y los administradores; se guarda en `enfoque.json` junto 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: ```bash # 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`. ```bash # 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. ```bash 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». ```bash 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/__.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.** ```bash ./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): ```bash cd /srv/projects/drogheda/tareas ls _borrados/ # __AAAAMMDDhhmmss.json mv _borrados/__.json .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](docs/inventario/index.md). 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`. ```bash 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 | ## B · Verificación después de desplegar ```bash # 1. el backend responde y sabe quién eres curl -s -u leo:PASS https://drogheda.helgen.online/api/whoami # {"user":"leo","admin":true} curl -s -u alan:PASS https://drogheda.helgen.online/api/whoami # {"user":"alan","admin":false} ``` Si `user` sale vacío, falta la línea `X-Remote-User` del paso 4. ```bash # 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í ```bash # 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: ```bash rsync -az leo@git.helgen.online:/srv/projects/drogheda/actas/ ~/respaldo-actas/ rsync -az leo@git.helgen.online:/srv/projects/drogheda/adjuntos/ ~/respaldo-fotos/ ``` ## 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 |