From f8045abb5b2f11cb7bc569e7f80ee63d45ce43b8 Mon Sep 17 00:00:00 2001 From: josedario87 Date: Fri, 21 Nov 2025 20:18:07 -0600 Subject: [PATCH] =?UTF-8?q?Documentar=20peculiaridades=20de=20implementaci?= =?UTF-8?q?=C3=B3n=20de=20PostgreSQL?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Agregar sección completa sobre autenticación md5 vs scram-sha-256 - Documentar race condition entre app y PostgreSQL con retry logic - Explicar idempotencia de scripts (schema vs seed) - Documentar persistencia de datos y volúmenes Docker - Incluir troubleshooting detallado de errores comunes - Agregar diagramas de arquitectura de inicialización - Documentar endpoints de debug temporales - Tabla de decisiones técnicas con alternativas descartadas - Queries útiles y comandos de backup/restore --- nuxt4/server/database/README.md | 665 +++++++++++++++++++++++--------- 1 file changed, 472 insertions(+), 193 deletions(-) diff --git a/nuxt4/server/database/README.md b/nuxt4/server/database/README.md index 69d348d..516c61a 100644 --- a/nuxt4/server/database/README.md +++ b/nuxt4/server/database/README.md @@ -1,62 +1,351 @@ -# Database - Scripts SQL +# Database - Documentación Completa Este directorio contiene los scripts SQL para inicializar y gestionar la base de datos PostgreSQL del sistema de trazabilidad. +## Tabla de Contenidos + +- [Archivos SQL](#archivos-sql) +- [⚠️ Peculiaridades de Implementación](#️-peculiaridades-de-implementación) + - [Autenticación PostgreSQL](#autenticación-postgresql) + - [Inicialización de la Base de Datos](#inicialización-de-la-base-de-datos) + - [Persistencia de Datos](#persistencia-de-datos) + - [Conexión desde Node.js](#conexión-desde-nodejs) + - [Endpoints de Debug](#endpoints-de-debug) +- [Ejecución de Scripts](#ejecución-de-scripts) +- [Troubleshooting](#troubleshooting) +- [Queries Útiles](#queries-útiles) + --- -## Archivos +## Archivos SQL + +### `00_configure_auth.sh` +Script Bash que configura la autenticación de PostgreSQL: +- Elimina configuración `scram-sha-256` (incompatible con driver `pg` de Node.js) +- Configura método `md5` en `pg_hba.conf` +- Se ejecuta automáticamente durante inicialización de PostgreSQL ### `01_schema.sql` Crea el esquema completo de la base de datos: - Tablas: `lotes`, `operaciones`, `operacion_lotes` - Índices para optimización -- Función `get_trazabilidad()` para queries recursivas +- Función recursiva `get_trazabilidad()` para queries de trazabilidad completa - Vista `vista_lotes_con_origen` - Constraints y validaciones +- **Idempotente**: Usa `CREATE TABLE IF NOT EXISTS` ### `02_seed.sql` -Datos de ejemplo que representan un flujo completo: +Datos de ejemplo que representan un flujo completo de trazabilidad: - Ingreso de uva (2086 kg) - Despulpado → primera, segunda, rechazos -- Oreado (con error de registro) +- Oreado (con error de registro intencional) - Ajuste de merma (1500 → 1480 kg) - Ajuste de tipo (oreado → presecado) - Reposo - Secado final (mezcla de 2 lotes = 2000 kg) +- **Total**: 10 lotes, 7 operaciones, 16 relaciones +- **Idempotente con TRUNCATE**: Limpia datos antes de insertar --- -## Ejecución Automática +## ⚠️ Peculiaridades de Implementación -Cuando usas **Docker Compose**, estos scripts se ejecutan automáticamente al iniciar PostgreSQL por primera vez gracias al montaje: +Esta sección documenta los desafíos técnicos encontrados y las soluciones implementadas durante el desarrollo. + +### Autenticación PostgreSQL + +#### ❌ Problema: Incompatibilidad scram-sha-256 + +**Contexto**: PostgreSQL 16 usa por defecto el método de autenticación `scram-sha-256`, pero el driver `pg` de Node.js tiene problemas de compatibilidad que resultan en: + +``` +Error code: 28P01 +FATAL: password authentication failed for user "seguidor" +``` + +#### ✅ Solución: Script de configuración automática + +**Archivo**: `00_configure_auth.sh` + +```bash +#!/bin/bash +set -e + +echo "Configurando autenticación de PostgreSQL..." + +# Eliminar configuración scram-sha-256 +sed -i '/scram-sha-256/d' "$PGDATA/pg_hba.conf" + +# Agregar configuración md5 +if ! grep -q "host all all all md5" "$PGDATA/pg_hba.conf"; then + echo "host all all all md5" >> "$PGDATA/pg_hba.conf" +fi + +echo "✓ Configuración de autenticación aplicada (md5)" +``` + +**Notas importantes**: +- El script se ejecuta **antes** de que PostgreSQL termine su inicialización +- Los cambios en `pg_hba.conf` se aplican automáticamente al finalizar el inicio +- No es necesario ejecutar `pg_ctl reload` manualmente +- El método `md5` es compatible con el driver `pg` de Node.js + +--- + +### Inicialización de la Base de Datos + +#### 📂 Scripts en `/docker-entrypoint-initdb.d/` + +Los scripts se ejecutan **solo si el volumen de datos está vacío** (primera vez): + +1. **`00_configure_auth.sh`** - Configura autenticación md5 +2. **`01_schema.sql`** - Crea estructura (tablas, funciones, vistas) +3. **`02_seed.sql`** - Inserta datos de ejemplo + +**Orden de ejecución**: Los archivos se ejecutan en orden alfabético/numérico. + +#### 🔄 Idempotencia de Scripts + +##### `01_schema.sql` - Totalmente Idempotente ✅ + +```sql +CREATE TABLE IF NOT EXISTS lotes ( + id UUID PRIMARY KEY DEFAULT gen_random_uuid(), + -- ... +); + +CREATE INDEX IF NOT EXISTS idx_lotes_tipo ON lotes(tipo); +``` + +- ✅ Puede ejecutarse múltiples veces sin errores +- ✅ No duplica tablas ni índices +- ✅ Seguro para re-ejecución + +##### `02_seed.sql` - Idempotente con TRUNCATE ⚠️ + +```sql +-- Línea 17: Limpia datos antes de insertar +TRUNCATE TABLE operacion_lotes, operaciones, lotes CASCADE; + +-- Luego inserta datos de ejemplo +INSERT INTO lotes (codigo, tipo, ...) VALUES (...); +``` + +**IMPORTANTE**: +- ⚠️ Si las tablas no existen, `TRUNCATE` falla +- ✅ Por eso el endpoint `seed-database` ejecuta **primero** el schema +- ✅ Puede ejecutarse múltiples veces si las tablas existen + +#### 🔍 Verificación en Workflow de Gitea Actions + +El workflow verifica si es necesario inicializar: + +```bash +TABLE_EXISTS=$(docker exec lotes-postgres psql -U seguidor -d seguidor_lotes \ + -tAc "SELECT EXISTS (SELECT FROM information_schema.tables WHERE table_name = 'lotes');") + +if [ "$TABLE_EXISTS" = "f" ]; then + echo "📝 Ejecutando scripts de inicialización..." + docker exec -i lotes-postgres psql -U seguidor -d seguidor_lotes < nuxt4/server/database/01_schema.sql + docker exec -i lotes-postgres psql -U seguidor -d seguidor_lotes < nuxt4/server/database/02_seed.sql +fi +``` + +**Comportamiento**: +- ✅ Primera vez: Ejecuta schema + seed +- ✅ Redeploys: Solo actualiza contenedor de app, **datos persisten** +- ✅ Después de `docker-compose down -v`: Reinicializa todo + +--- + +### Persistencia de Datos + +#### 💾 Volumen Docker ```yaml +# docker-compose.yml +volumes: + postgres_data: # Volumen nombrado + +services: + postgres: + volumes: + - postgres_data:/var/lib/postgresql/data +``` + +**Comportamiento**: +- ✅ Datos persisten entre `docker-compose down` y `docker-compose up` +- ✅ Datos persisten entre redespliegues del workflow +- ❌ Datos se pierden con `docker-compose down -v` (elimina volúmenes) + +#### 🔄 Resetear a Estado Inicial + +**Opción 1: Eliminar volumen (desde servidor)** +```bash +docker-compose --project-name lotes down -v +# Próximo deploy reinicializará automáticamente +``` + +**Opción 2: Usar botones de debug (desde web)** +1. Click en "🗑️ BORRAR TODA LA BD" → Elimina todas las tablas +2. Click en "🌱 CARGAR DATOS DE EJEMPLO" → Recrea schema + seed +3. Recarga la página + +**Opción 3: Trigger redeploy después de borrar** +```bash +# 1. Click "🗑️ BORRAR TODA LA BD" en la web +# 2. Trigger redeploy +git commit --allow-empty -m "Trigger reinit DB" && git push +# El workflow detectará tablas faltantes y ejecutará schema + seed +``` + +--- + +### Conexión desde Node.js + +#### 🔌 Pool de Conexiones + +**Configuración en `server/utils/db.ts`**: + +```typescript +const config = { + user: process.env.POSTGRES_USER || 'seguidor', + password: process.env.POSTGRES_PASSWORD || 'seguidor_password', + database: process.env.POSTGRES_DB || 'seguidor_lotes', + host: process.env.POSTGRES_HOST || 'postgres', + port: parseInt(process.env.POSTGRES_PORT || '5432'), + max: 20, // Máximo de conexiones en el pool + idleTimeoutMillis: 30000, // 30s timeout para conexiones idle + connectionTimeoutMillis: 10000, // 10s timeout para establecer conexión +} +``` + +**Peculiaridades**: + +1. **Timeout de 10 segundos**: Necesario porque PostgreSQL puede tardar en aplicar configuración de autenticación + +2. **Retry Logic Automático**: + ```typescript + // Verifica conexión inicial con 5 reintentos + let retries = 5 + const tryConnect = async () => { + try { + const client = await pool!.connect() + console.log('✅ Conexión inicial a PostgreSQL exitosa') + client.release() + } catch (err: any) { + retries-- + if (retries > 0) { + console.log(`⚠️ Conexión falló, reintentando... (${retries} intentos)`) + setTimeout(tryConnect, 2000) // Reintentar en 2s + } + } + } + ``` + +3. **Logs solo en desarrollo**: + ```typescript + if (process.env.NODE_ENV !== 'production') { + pool.on('connect', () => { + console.log('Nueva conexión establecida con PostgreSQL') + }) + } + ``` + +#### ⚡ Race Condition: App vs PostgreSQL + +**Problema**: Aunque docker-compose tiene `depends_on` con `service_healthy`, el healthcheck solo verifica que PostgreSQL **responde**, no que terminó de ejecutar los scripts de inicialización. + +**Timeline Real**: +``` +T+0s: PostgreSQL inicia +T+2s: PostgreSQL responde a pg_isready → healthcheck ✅ +T+2s: App Nuxt inicia e intenta conectarse +T+3s: PostgreSQL ejecuta 00_configure_auth.sh (cambia auth) +T+4s: Primera conexión de app FALLA (todavía usa scram-sha-256) +T+5s: Script termina, auth está configurado +T+7s: Retry logic de app conecta exitosamente ✅ +``` + +**Solución**: El retry logic compensa esta race condition automáticamente. + +--- + +### Endpoints de Debug + +#### ⚠️ Endpoints Temporales + +Estos endpoints están marcados como **TEMPORALES** y **NO DEBEN ELIMINARSE** sin consultar a Dario/Draganel/nucleo000. + +#### `POST /api/debug/reset-database` + +**Función**: Elimina completamente todas las tablas de la base de datos. + +**Implementación**: +```typescript +await client.query('DROP TABLE IF EXISTS operacion_lotes CASCADE') +await client.query('DROP TABLE IF EXISTS operaciones CASCADE') +await client.query('DROP TABLE IF EXISTS lotes CASCADE') +await client.query('DROP FUNCTION IF EXISTS get_trazabilidad CASCADE') +await client.query('DROP VIEW IF EXISTS vista_lotes_con_origen CASCADE') +``` + +**Notas**: +- Usa `DROP TABLE` (no `TRUNCATE`) para que el workflow detecte la ausencia de tablas +- Después de usar, el próximo deploy reinicializará automáticamente +- Requiere confirmación del usuario en el frontend + +#### `POST /api/debug/seed-database` + +**Función**: Recrea schema y carga datos de ejemplo. + +**Implementación**: +```typescript +// 1. Ejecutar schema (crea tablas si no existen) +const schemaSQL = await readFile('server/database/01_schema.sql', 'utf-8') +await client.query(schemaSQL) + +// 2. Ejecutar seed (truncate + insert) +const seedSQL = await readFile('server/database/02_seed.sql', 'utf-8') +await client.query(seedSQL) +``` + +**Peculiaridad**: Los archivos SQL deben estar en el contenedor de la app + +**Dockerfile**: +```dockerfile +# Copy SQL files for seed endpoint +COPY --from=builder /app/server/database /app/server/database +``` + +Sin esta línea, el endpoint devuelve `ENOENT: no such file or directory`. + +--- + +## Ejecución de Scripts + +### Automática (Docker Compose) + +```yaml +# docker-compose.yml volumes: - ./nuxt4/server/database:/docker-entrypoint-initdb.d:ro ``` -PostgreSQL ejecuta todos los archivos `.sql` en orden alfabético dentro de `/docker-entrypoint-initdb.d/`. +PostgreSQL ejecuta todos los archivos `.sql` y `.sh` en orden alfabético dentro de `/docker-entrypoint-initdb.d/` **solo la primera vez**. -**Orden de ejecución:** -1. `01_schema.sql` - Crea estructura -2. `02_seed.sql` - Inserta datos de ejemplo - ---- - -## Ejecución Manual - -### Opción 1: Desde el contenedor Docker +### Manual - Desde el contenedor Docker ```bash # Conectarse al contenedor -docker exec -it seguidorDeLotes-postgres psql -U seguidor -d seguidor_lotes +docker exec -it lotes-postgres psql -U seguidor -d seguidor_lotes # Dentro de psql, ejecutar: \i /docker-entrypoint-initdb.d/01_schema.sql \i /docker-entrypoint-initdb.d/02_seed.sql ``` -### Opción 2: Desde tu máquina local +### Manual - Desde tu máquina local ```bash # Asegúrate de tener psql instalado @@ -64,147 +353,113 @@ psql -h localhost -U seguidor -d seguidor_lotes -f 01_schema.sql psql -h localhost -U seguidor -d seguidor_lotes -f 02_seed.sql ``` -### Opción 3: Copiar y pegar en pgAdmin o DBeaver - -Abre los archivos `.sql` en tu cliente SQL favorito y ejecútalos directamente. - ---- - -## Reiniciar la Base de Datos - -Si necesitas empezar desde cero: +### Manual - Vía API (endpoints de debug) ```bash -# Detener contenedores y eliminar volúmenes -docker-compose down -v +# Resetear BD +curl -X POST https://lotes.nucleoriofrio.com/api/debug/reset-database -# Volver a iniciar (ejecutará scripts automáticamente) -docker-compose up -d - -# Ver logs para confirmar -docker logs -f seguidorDeLotes-postgres +# Cargar datos de ejemplo +curl -X POST https://lotes.nucleoriofrio.com/api/debug/seed-database ``` --- -## Verificar que todo está correcto +## Troubleshooting -### 1. Conectarse a la base de datos +### ❌ Error: "password authentication failed for user seguidor" +**Causas posibles**: + +1. **Primera carga del sistema** (normal) + - PostgreSQL todavía está configurando autenticación + - Solución: Esperar ~5 segundos, el retry logic se encarga + - Logs: `⚠️ Conexión falló, reintentando...` seguido de `✅ Conexión exitosa` + +2. **Volumen de postgres de un deploy anterior con scram-sha-256** + - Solución: Eliminar volumen y redeploy + ```bash + docker-compose --project-name lotes down -v + git commit --allow-empty -m "Reinit DB" && git push + ``` + +3. **Variables de entorno incorrectas** + - Verificar en Gitea > Settings > Actions > Secrets/Variables + - Variables requeridas: `POSTGRES_USER`, `POSTGRES_PASSWORD`, `POSTGRES_DB` + +### ❌ Error: "relation 'lotes' does not exist" + +**Causas posibles**: + +1. **Base de datos no inicializada** + - Verificar logs del workflow: ¿se ejecutó la inicialización? + - Solución: Click en "🌱 CARGAR DATOS DE EJEMPLO" + +2. **Múltiples contenedores PostgreSQL** + - App conectándose al contenedor equivocado + - Solución: Limpiar contenedores huérfanos + ```bash + docker ps -a | grep postgres + docker rm -f [contenedores antiguos] + ``` + +3. **Usaste TRUNCATE en lugar de DROP** + - Si usaste el botón de borrar BD pero las tablas quedaron vacías + - Solución: Click en "🌱 CARGAR DATOS DE EJEMPLO" (ahora ejecuta schema primero) + +### ❌ Error: "ENOENT: no such file or directory, open '/app/server/database/02_seed.sql'" + +**Causa**: Archivos SQL no copiados al contenedor de la app + +**Solución**: Verificar que Dockerfile incluya: +```dockerfile +COPY --from=builder /app/server/database /app/server/database +``` + +Luego rebuild: ```bash -docker exec -it seguidorDeLotes-postgres psql -U seguidor -d seguidor_lotes +git commit -am "Fix Dockerfile" && git push ``` -### 2. Listar tablas +### 📊 Logs: Múltiples "Nueva conexión establecida con PostgreSQL" -```sql -\dt -``` +**Comportamiento**: Es **normal y correcto** en desarrollo -**Deberías ver:** -``` - List of relations - Schema | Name | Type | Owner ---------+------------------+-------+---------- - public | lotes | table | seguidor - public | operacion_lotes | table | seguidor - public | operaciones | table | seguidor -``` +- El pool crea múltiples conexiones (configurado para max 20) +- Cada endpoint que hace query puede obtener una conexión del pool -### 3. Contar registros - -```sql -SELECT - (SELECT COUNT(*) FROM lotes) as total_lotes, - (SELECT COUNT(*) FROM operaciones) as total_operaciones, - (SELECT COUNT(*) FROM operacion_lotes) as total_relaciones; -``` - -**Deberías ver algo como:** -``` - total_lotes | total_operaciones | total_relaciones --------------+-------------------+------------------ - 9 | 8 | 16 -``` - -### 4. Ver lotes creados - -```sql -SELECT codigo, tipo, cantidad_kg FROM lotes ORDER BY fecha_creado; -``` - -**Deberías ver:** -``` - codigo | tipo | cantidad_kg ------------+----------------------+------------- - UVA-001 | uva | 2086.00 - PRIM-001 | despulpado_primera | 1500.00 - SEG-001 | despulpado_segunda | 400.00 - RECH-001 | despulpado_rechazos | 150.00 - ORE-001 | oreado | 1500.00 - ORE-001A | oreado | 1480.00 - PRE-001 | presecado | 1480.00 - REP-001 | reposo | 1480.00 - REP-002 | reposo | 520.00 - SEC-001 | secado | 2000.00 -``` - -### 5. Probar la función de trazabilidad - -```sql -SELECT * FROM get_trazabilidad( - (SELECT id FROM lotes WHERE codigo = 'SEC-001') -); -``` - -**Deberías ver:** Todo el historial del lote `SEC-001` desde el ingreso de uva. - ---- - -## Estructura de las Tablas - -### Tabla `lotes` - -```sql -CREATE TABLE lotes ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - codigo TEXT UNIQUE, - tipo TEXT NOT NULL, - fecha_creado TIMESTAMPTZ NOT NULL DEFAULT NOW(), - lugar_id INTEGER, - cantidad_kg NUMERIC(10,2), - meta JSONB -); -``` - -### Tabla `operaciones` - -```sql -CREATE TABLE operaciones ( - id UUID PRIMARY KEY DEFAULT uuid_generate_v4(), - tipo TEXT NOT NULL, - fecha TIMESTAMPTZ NOT NULL DEFAULT NOW(), - lugar_id INTEGER, - meta JSONB -); -``` - -### Tabla `operacion_lotes` - -```sql -CREATE TABLE operacion_lotes ( - operacion_id UUID NOT NULL REFERENCES operaciones(id) ON DELETE CASCADE, - lote_id UUID NOT NULL REFERENCES lotes(id) ON DELETE CASCADE, - rol TEXT NOT NULL CHECK (rol IN ('input', 'output')), - cantidad_kg NUMERIC(10,2), - PRIMARY KEY (operacion_id, lote_id, rol) -); +**Si quieres reducir logs**: Ya está configurado para no mostrar en producción +```typescript +if (process.env.NODE_ENV !== 'production') { + pool.on('connect', () => console.log('Nueva conexión...')) +} ``` --- ## Queries Útiles +### Verificar que todo está correcto + +```sql +-- 1. Listar tablas +\dt + +-- 2. Contar registros +SELECT + (SELECT COUNT(*) FROM lotes) as total_lotes, + (SELECT COUNT(*) FROM operaciones) as total_operaciones, + (SELECT COUNT(*) FROM operacion_lotes) as total_relaciones; + +-- 3. Ver lotes creados +SELECT codigo, tipo, cantidad_kg FROM lotes ORDER BY fecha_creado; + +-- 4. Probar función de trazabilidad +SELECT * FROM get_trazabilidad( + (SELECT id FROM lotes WHERE codigo = 'SEC-001') +); +``` + ### Ver todas las operaciones de un lote ```sql @@ -219,10 +474,9 @@ WHERE ol.lote_id = (SELECT id FROM lotes WHERE codigo = 'SEC-001') ORDER BY o.fecha; ``` -### Ver lotes que se usaron para crear un lote específico (inputs directos) +### Ver inputs directos de un lote ```sql --- Inputs directos del lote SEC-001 SELECT l.codigo, l.tipo, @@ -237,7 +491,7 @@ WHERE ol_out.lote_id = (SELECT id FROM lotes WHERE codigo = 'SEC-001') AND ol_in.rol = 'input'; ``` -### Ver estadísticas de un período +### Estadísticas de operaciones ```sql SELECT @@ -252,29 +506,57 @@ ORDER BY total DESC; --- -## Migraciones Futuras +## Arquitectura de Inicialización -Cuando necesites hacer cambios al esquema en producción: +``` +┌─────────────────────────────────────────────────────────────────┐ +│ INICIALIZACIÓN COMPLETA (solo primera vez) │ +└─────────────────────────────────────────────────────────────────┘ -1. **Crear archivo de migración** (ej: `03_add_lugares_table.sql`) -2. **NO modificar** `01_schema.sql` ni `02_seed.sql` directamente -3. **Aplicar migración manualmente** en producción +1. docker-compose up + ↓ +2. PostgreSQL container inicia + ↓ +3. Volumen postgres_data vacío? → SÍ + ↓ +4. Ejecuta /docker-entrypoint-initdb.d/ en orden: + │ + ├─ 00_configure_auth.sh → Cambia pg_hba.conf a md5 + ├─ 01_schema.sql → Crea tablas, funciones, vistas + └─ 02_seed.sql → Inserta 10 lotes, 7 ops, 16 rels + ↓ +5. PostgreSQL termina inicio → healthcheck ✅ + ↓ +6. App container inicia + ↓ +7. App intenta conectar (puede fallar 1-2 veces) + ↓ +8. Retry logic espera y reconecta + ↓ +9. ✅ Sistema funcionando -Ejemplo de migración: -```sql --- 03_add_lugares_table.sql -CREATE TABLE IF NOT EXISTS lugares ( - id SERIAL PRIMARY KEY, - nombre TEXT NOT NULL, - tipo TEXT, -- patio, pila, bodega, etc. - capacidad_kg NUMERIC -); +┌─────────────────────────────────────────────────────────────────┐ +│ REDESPLIEGUE (datos persisten) │ +└─────────────────────────────────────────────────────────────────┘ --- Agregar foreign key a lotes -ALTER TABLE lotes - ADD CONSTRAINT fk_lotes_lugar - FOREIGN KEY (lugar_id) REFERENCES lugares(id); +1. git push → Workflow inicia + ↓ +2. Build nueva imagen Docker + ↓ +3. docker-compose down (sin -v) → PostgreSQL se detiene + ↓ +4. docker-compose up → PostgreSQL reinicia + ↓ +5. Volumen postgres_data existe? → SÍ + ↓ +6. PostgreSQL lee datos existentes + ↓ +7. NO ejecuta scripts de /docker-entrypoint-initdb.d/ + ↓ +8. App container inicia con nueva imagen + ↓ +9. ✅ Sistema funcionando (con datos previos) ``` --- @@ -284,55 +566,52 @@ ALTER TABLE lotes ### Hacer backup ```bash -docker exec seguidorDeLotes-postgres pg_dump -U seguidor seguidor_lotes > backup_$(date +%Y%m%d).sql +# Backup completo +docker exec lotes-postgres pg_dump -U seguidor seguidor_lotes > backup_$(date +%Y%m%d).sql + +# Backup solo schema (sin datos) +docker exec lotes-postgres pg_dump -U seguidor -s seguidor_lotes > schema_$(date +%Y%m%d).sql + +# Backup solo datos +docker exec lotes-postgres pg_dump -U seguidor -a seguidor_lotes > data_$(date +%Y%m%d).sql ``` ### Restaurar backup ```bash -cat backup_20251121.sql | docker exec -i seguidorDeLotes-postgres psql -U seguidor -d seguidor_lotes +# Restaurar desde archivo +cat backup_20251121.sql | docker exec -i lotes-postgres psql -U seguidor -d seguidor_lotes + +# Restaurar directo desde servidor +docker exec -i lotes-postgres psql -U seguidor -d seguidor_lotes < backup.sql ``` --- -## Troubleshooting +## Resumen de Decisiones Técnicas -### "relation lotes does not exist" - -Los scripts no se ejecutaron. Verificar: -```bash -docker logs seguidorDeLotes-postgres -``` - -Si ves errores, eliminar volumen y reiniciar: -```bash -docker-compose down -v -docker-compose up -d -``` - -### "permission denied for schema public" - -Problema de permisos. Conectarse como superuser: -```bash -docker exec -it seguidorDeLotes-postgres psql -U postgres -d seguidor_lotes - --- Dar permisos -GRANT ALL ON SCHEMA public TO seguidor; -GRANT ALL ON ALL TABLES IN SCHEMA public TO seguidor; -``` - -### Los datos de ejemplo se duplican - -`02_seed.sql` hace `TRUNCATE` al inicio. Si no quieres perder datos, comenta esa línea. +| Decisión | Razón | Alternativa Descartada | +|----------|-------|------------------------| +| md5 en lugar de scram-sha-256 | Compatibilidad con driver pg de Node.js | Actualizar driver (requiere cambios mayores) | +| Retry logic en pool | Compensa race condition de inicialización | depends_on custom healthcheck (complejo) | +| Timeout de 10s | PostgreSQL puede tardar en configurar auth | 2s (insuficiente) | +| DROP TABLE en reset | Workflow detecta ausencia y reinicializa | TRUNCATE (deja tablas vacías) | +| seed ejecuta schema primero | Funciona después de borrar BD | Solo seed (falla si no hay tablas) | +| Scripts SQL en app container | Permite endpoint de seed | Solo en postgres (no accesible desde app) | +| Volumen nombrado | Persistencia entre redeploys | Volumen bind mount (menos portable) | --- ## Referencias -- [PostgreSQL JSON Functions](https://www.postgresql.org/docs/current/functions-json.html) -- [Recursive Queries (CTE)](https://www.postgresql.org/docs/current/queries-with.html) -- [Docker Init Scripts](https://hub.docker.com/_/postgres) +- **PostgreSQL Authentication**: https://www.postgresql.org/docs/16/auth-pg-hba-conf.html +- **node-postgres (pg)**: https://node-postgres.com/ +- **Docker Init Scripts**: https://hub.docker.com/_/postgres (sección "Initialization scripts") +- **Pool de Conexiones**: https://node-postgres.com/apis/pool +- **Recursive Queries (CTE)**: https://www.postgresql.org/docs/current/queries-with.html --- **Última actualización**: 2025-11-21 +**Autor**: Claude Code (claudeCode0@nucleoriofrio.com) +**Proyecto**: Seguidor de Lotes - Sistema de Trazabilidad de Café