El problema anterior era que pg_dump genera archivos SQL con
comandos de psql (\connect, \set, etc.) que no son SQL válido
para ejecutar con el driver de Node.js.
Cambios:
- Guardar el archivo .sql temporalmente en /tmp
- Ejecutar psql -f archivo.sql para importar
- Limpiar el archivo temporal después
- Manejar mensajes de psql correctamente (stderr != error)
- Agregar validación para psql no disponible
Ahora la importación funciona correctamente con archivos
generados por pg_dump.
Implementa la capacidad de restaurar la base de datos desde
un archivo SQL de backup exportado previamente.
Cambios:
Backend:
- Nuevo endpoint POST /api/debug/import-database.post.ts
- Recibe archivo .sql via multipart/form-data
- Ejecuta el SQL del backup (que incluye DROP y CREATE)
- Reemplaza completamente la base de datos existente
Frontend:
- Nuevo botón verde "📥 IMPORTAR BACKUP"
- Input file oculto con accept=".sql"
- Validación de extensión de archivo
- Confirmación con advertencia clara
- Estado de carga durante importación
Flujo de uso:
1. Usuario hace click en "📥 IMPORTAR BACKUP"
2. Selecciona archivo .sql previamente exportado
3. Confirma que desea reemplazar toda la BD
4. Sistema ejecuta el SQL completo
5. Muestra mensaje de éxito/error
6. Usuario recarga la página
Esto completa el ciclo backup/restore permitiendo
recuperación completa del estado de la base de datos.
El endpoint ahora puede cargar datos de ejemplo en dos escenarios:
1. Cuando se eliminó la estructura completa (DROP):
- Detecta que las tablas no existen
- Ejecuta el schema completo (01_schema.sql)
- Luego carga los datos de ejemplo (02_seed.sql)
2. Cuando solo se eliminaron los datos (TRUNCATE):
- Detecta que las tablas existen
- Limpia los datos con TRUNCATE CASCADE
- Luego carga los datos de ejemplo
Esto hace que el botón "CARGAR DATOS DE EJEMPLO" sea más
robusto y funcione en cualquier estado de la base de datos.
Instala postgresql-client en la imagen de producción para
que el endpoint de exportación de backup pueda usar pg_dump.
Esto permite generar backups completos de la base de datos
desde el botón de debug en la interfaz.
- Agregar botón 'LIMPIAR DATOS' que hace TRUNCATE de tablas sin borrar estructura
- Agregar botón 'EXPORTAR BACKUP' que descarga pg_dump completo de la BD
- Crear endpoint POST /api/debug/clear-data para TRUNCATE CASCADE
- Crear endpoint POST /api/debug/export-database para pg_dump con descarga
- Mantener estructura de botones temporales de debug existentes
- Incluir confirmaciones y manejo de errores apropiados
- Agregar flujo 5: Las Nubes (Geisha) + El Paraíso (Castillo) → SEC-EXOTIC-001
- Agregar flujo 6: Santa Rita (Caturra Rojo) → División → SEC-SRT-PREM-001 + SEC-SRT-STD-001
- Agregar flujo 7: Trinidad + San José + Villa Rosa → Triple Blend → SEC-TRIPLE-001
- Agregar flujo 8: Mezcla de segundas calidades → SEC-COMERCIAL-001
- Implementar filtro soloFinales en queries, API y composable
- Modificar tab Grafos para mostrar solo lotes finales (sin hijos)
- Actualizar descripción de tab Grafos para clarificar el filtro
- Total: 7 lotes finales de secado para visualización de grafos
Ahora el formulario de crear operación permite crear nuevos lotes de
entrada directamente desde el paso 2, sin necesidad de salir del modal.
Cambios:
- Agregar botón "Nuevo lote de entrada" en el paso 2
- Mostrar formulario inline para crear lote con código, tipo y cantidad
- Al crear el lote, se agrega automáticamente a la lista de disponibles
- Se selecciona automáticamente como input de la operación
- Importar createLote del composable useLotes
- Agregar estado showCreateInputForm y creatingInput
- Implementar funciones cancelCreateInput y handleCreateInput
Beneficios:
- Flujo más ágil sin interrupciones
- Consistencia con la creación de lotes de output
- Mejor experiencia de usuario
Cambios realizados:
1. Favicon:
- Actualizar configuración en app.vue para usar iconos PNG correctos
- Agregar links con tamaños 32x32 y 16x16
- Actualizar theme-color a #16a34a (verde del proyecto)
2. Modal de Crear Operación:
- Reestructurar con slots #header y #body para scroll correcto
- Extraer header del Form.vue y moverlo al modal
- Eliminar UCard del componente Form.vue
- Agregar max-h-[80vh] para limitar altura
- Ahora muestra scrollbar vertical cuando el contenido excede el espacio
3. USelect de filtro de operaciones:
- Corregir de :options a :items (API correcta de NuxtUI v4)
- Agregar label-key y value-key
- Agregar computed selectOptions (igual que en Lotes)
- Cambiar filtroTipo de ref('') a ref<string | null>(null)
- Ahora el filtro funciona correctamente
Archivos modificados:
- app/app.vue: Configuración favicon y modal operaciones
- app/components/operaciones/Form.vue: Eliminar UCard
- app/components/operaciones/Table.vue: Corregir USelect
Cambios realizados:
- Actualizar manifest de PWA con nombre, descripción y tema correctos
- Reemplazar iconos genéricos con iconos personalizados del proyecto
- Agregar iconos en todos los tamaños necesarios (16x16 hasta 512x512)
- Actualizar apple-touch-icon con el icono de 180x180
- Cambiar theme_color a verde (#16a34a) acorde a la identidad del proyecto
Los iconos ahora representan la marca "Seguidor de Lotes - Trazabilidad
de Café" del Beneficio Río Frío.
El componente LotesTrazabilidad no se estaba renderizando porque
no estaba dentro del slot #body. El UModal de NuxtUI requiere que
el contenido esté explícitamente en el slot #body para que se
renderice correctamente.
Cambios:
- Envolver LotesTrazabilidad en <template #body>
- El modal ahora muestra correctamente el contenido con scroll vertical
- Corregir referencia a colorMode (agregar .value)
- Optimizar renderizado de aristas usando paths SVG
- Mejorar posicionamiento de nodos con agrupación por padre
- Evitar solapamiento de nodos hermanos
- Ajustar cálculo dinámico del ancho del SVG
- Mover v-if al UCard completo para renderizado consistente
- Agregar configuración de UI con ancho max-w-2xl
- Remover v-if redundantes internos
- Seguir el patrón de otros modales que funcionan correctamente
Los componentes LotesTable y OperacionesTable usan UTable de Nuxt UI,
que internamente usa @tanstack/table-core. Esta librería no puede
renderizarse en el servidor (SSR), causando error 500.
Solución: Envolver los componentes en <ClientOnly> para que solo se
rendericen en el navegador.
- Crear plugin error-handler.ts para capturar todos los errores
- Captura errores de app:error, vue:error y errorHandler
- Agregar logs en script setup de componentes
- Logs antes y después de llamar a useLotes()
- Esto nos mostrará exactamente dónde crashea la app
- Logs en useLotes() para ver cuándo se llama
- Logs en fetchLotes() para rastrear el flujo
- Logs en API /api/lotes para ver requests del servidor
- Todos los logs con emojis para fácil identificación:
🔵 = Cliente/Composable
🟦 = Servidor/API
❌ = Errores
El problema era que useToast() no funciona en Server-Side Rendering.
Cuando los componentes se renderizaban en el servidor, crasheaba con error 500.
Cambios:
- Hacer que toast sea opcional: process.client ? useToast() : null
- Cambiar todos toast.add() a toast?.add()
- Ahora el composable funciona tanto en servidor como en cliente
- Agregar try-catch en loadLotes/loadOperaciones
- Agregar try-catch en onMounted y watch
- Agregar estado de error y mostrar mensaje en UI
- Agregar console.log detallados para debug
- Mostrar errores en tarjeta roja sin crashear la app
- Restaurar LotesTable completo con onMounted y watch
- Habilitar carga automática de datos
- Base de datos recreada con credenciales correctas
- Conexión PostgreSQL funcionando correctamente