docs: registrar cómo se sostiene la persistencia en producción

El VOLUME anónimo del Dockerfile y el volumen con nombre de Coolify son dos piezas
del mismo mecanismo: quitar una y no poner la otra deja la base efímera. Queda
documentado junto con el respaldo diario y por qué usa VACUUM INTO en vez de cp.

Co-Authored-By: Claude Opus 5 (1M context) <[email protected]>
This commit is contained in:
AgendaPro Dev
2026-08-29 01:09:04 -06:00
co-authored by Claude Opus 5
parent 4f566ddde7
commit dcbf750c09
+23
View File
@@ -409,6 +409,29 @@ prueba contra producción o retrasa el chunk a propósito con `route()`.
- `data/`, `dist/`, `screenshots/`, `.cache/`, `*.log` y `.opencode/` están gitignorados y son
regenerables; no los versiones ni los tomes como fuente de verdad.
## Persistencia en producción
`data/agendapro.db` es el estado del producto y el despliegue **no** lo recrea. Dos
piezas lo sostienen, y hay que tocarlas juntas:
- **El `Dockerfile` NO declara `VOLUME /app/data`.** Esa instrucción hace que Docker
fabrique un volumen **anónimo** en cada arranque, y Coolify los purga al recrear el
contenedor: cada despliegue estrenaba base vacía, `ensureSeed()` la resembraba y se
perdían citas, clientes y todo lo configurado en Ajustes, sin error ni aviso. Se
verificó comparando el nombre del volumen entre despliegues: cambiaba cada vez y no
quedaba ningún huérfano con datos. **No lo reintroduzcas.**
- **La persistencia la aporta el volumen con nombre declarado en Coolify**
(`s30f7egdlkx4wyjp59o1iunc-agendamax-data` → `/app/data`, fila de
`local_persistent_volumes`). Ojo: la API de Coolify 4.1.2 devuelve 404 en
`/applications/*`, así que eso se configura por la UI o por su base de datos, no por
API. Si despliegas en otro host, declara allí un volumen equivalente: sin él la base
es efímera otra vez.
Respaldo: `/root/scripts/backup-agendamax.sh` en el host Proxmox, por cron diario a las
03:30, con retención de 14 días en `/root/backups/agendamax/`. Usa `VACUUM INTO`, no
`cp`: la base corre en WAL y copiar el `.db` en caliente da una foto anterior al último
checkpoint. El script verifica `integrity_check` y descarta el respaldo si falla.
## Seguridad
Esto es una **demo**: token trivial, contraseñas en claro, sin rate-limiting ni sesiones reales, y