Eliminados hacks de autenticación md5 y configuración manual de pg_hba.conf. Ahora usa NUXT_POSTGRES_URL como secret de Gitea para conexión directa.
Seguidor de Lotes - Sistema de Trazabilidad de Café
Sistema completo de trazabilidad para café, desde ingreso de uva hasta secado final, implementando un modelo de grafo (DAG) para rastrear transformaciones, divisiones y combinaciones de lotes.
🌐 URL: https://lotes.nucleoriofrio.com
🎯 Características Principales
- ✅ Trazabilidad Completa: Rastreo desde ingreso de uva hasta café secado
- ✅ Modelo de Grafo (DAG): Soporta divisiones (1→N), combinaciones (N→1) y transformaciones (1→1)
- ✅ API REST Completa: 11 endpoints para gestión de lotes y operaciones
- ✅ Frontend Interactivo: Interfaz con Nuxt UI para visualización y gestión
- ✅ Función Recursiva de Trazabilidad: Consulta SQL que recorre todo el historial
- ✅ PostgreSQL sin ORM: Queries directas con driver
pg - ✅ Autenticación Authentik: Protección mediante Proxy Outpost
- ✅ CI/CD Automático: Gitea Actions para build y deploy
📊 Modelo de Datos
Estructura del Grafo
El sistema usa 3 tablas principales que forman un grafo dirigido acíclico (DAG):
┌─────────────┐ ┌──────────────────┐ ┌─────────────┐
│ LOTES │◄─────│ OPERACION_LOTES │─────►│ OPERACIONES │
│ │ │ │ │ │
│ - id │ │ - operacion_id │ │ - id │
│ - codigo │ │ - lote_id │ │ - tipo │
│ - tipo │ │ - rol (in/out) │ │ - fecha │
│ - cantidad │ │ - cantidad_kg │ │ - meta │
└─────────────┘ └──────────────────┘ └─────────────┘
Tipos de Operaciones Soportadas
- Ingreso: Recepción de uva del productor
- Despulpado: 1→3 (genera primera, segunda, rechazos)
- Oreado: 1→1 (reducción de humedad en patio)
- Presecado: 1→1 (reducción adicional de humedad)
- Reposo: 1→1 (estabilización en bodega)
- Secado: N→1 (combinación de lotes para secado final)
- Ajustes: Corrección de mermas o tipos
Ejemplo de Flujo
UVA-001 (2086kg)
│
├─[Despulpado]─┬─► PRIM-001 (1500kg)
│ ├─► SEG-001 (400kg)
│ └─► RECH-001 (150kg)
│
└─[Oreado]────► ORE-001 (1500kg)
│
├─[Ajuste merma]────► ORE-001A (1480kg)
│
├─[Ajuste tipo]─────► PRE-001 (1480kg)
│
└─[Reposo]──────────► REP-001 (1480kg)
│
├─[Secado]─► SEC-001 (2000kg)
│
REP-002 (520kg)
🚀 Inicio Rápido
Requisitos Previos
- Docker y Docker Compose
- Gitea con Actions habilitado
- Traefik con red
traefik-network - Authentik con Proxy Outpost configurado
Despliegue Automático
-
Fork/Clone del repositorio en tu Gitea
-
Configurar variables en Gitea (
Settings > Actions):Secrets:
REGISTRY_USERNAME- Usuario del registro DockerREGISTRY_PASSWORD- Contraseña del registroPOSTGRES_PASSWORD- Contraseña de PostgreSQL
Variables:
REGISTRY_URL-gitea.nucleoriofrio.comAPP_NAME-lotesAPP_DOMAIN-lotes.nucleoriofrio.comNUXT_PUBLIC_APP_URL-https://lotes.nucleoriofrio.comNUXT_POSTGRES_URL-postgres://seguidor:seguidor_password@postgres:5432/seguidor_lotesPOSTGRES_USER-seguidorPOSTGRES_DB-seguidor_lotesPOSTGRES_PORT-5432
-
Push al repositorio - El workflow automáticamente:
- Construye la imagen Docker
- Sube la imagen al registro
- Despliega con docker-compose
- Inicializa PostgreSQL (solo primera vez)
- Carga datos de ejemplo (solo primera vez)
📁 Estructura del Proyecto
.
├── nuxt4/
│ ├── app/
│ │ ├── components/
│ │ │ ├── lotes/ # Componentes de lotes
│ │ │ ├── operaciones/ # Componentes de operaciones
│ │ │ └── auth/ # Componentes de autenticación
│ │ ├── composables/
│ │ │ ├── useLotes.ts # Lógica de negocio
│ │ │ └── useAuthentik.ts # Autenticación
│ │ └── app.vue # Aplicación principal (con botones debug)
│ ├── server/
│ │ ├── api/
│ │ │ ├── lotes/ # Endpoints de lotes (6)
│ │ │ ├── operaciones/ # Endpoints de operaciones (3)
│ │ │ └── debug/ # ⚠️ Endpoints debug temporales (2)
│ │ ├── utils/
│ │ │ ├── db.ts # Pool de PostgreSQL
│ │ │ └── queries.ts # Funciones SQL
│ │ └── database/
│ │ ├── 01_schema.sql # Esquema DB
│ │ └── 02_seed.sql # Datos de ejemplo
│ └── package.json
├── docker-compose.yml # Servicios (app + postgres)
├── .gitea/workflows/
│ └── build-and-deploy.yml # CI/CD
└── README.md
🔌 API Endpoints
Lotes
GET /api/lotes- Listar lotes (con filtros)POST /api/lotes- Crear loteGET /api/lotes/:id- Obtener lote específicoPATCH /api/lotes/:id- Actualizar loteDELETE /api/lotes/:id- Eliminar loteGET /api/lotes/:id/trazabilidad- Obtener trazabilidad completa
Operaciones
GET /api/operaciones- Listar operacionesPOST /api/operaciones- Crear operación con lotesGET /api/operaciones/:id- Obtener operación específica
Debug (⚠️ Temporales)
POST /api/debug/reset-database- Elimina todas las tablas (DROP)POST /api/debug/seed-database- Carga datos de ejemplo
Nota: Estos endpoints están marcados como temporales. No eliminar sin consultar.
Ejemplo de Respuesta - Trazabilidad
{
"success": true,
"data": {
"historial": [
{
"lote_id": "...",
"codigo": "SEC-001",
"tipo": "secado",
"profundidad": 0,
"operacion_tipo": "secado",
"fecha_operacion": "2025-11-20T01:12:19.489Z"
},
// ... historial completo hasta origen
],
"estadisticas": {
"total_ancestros": 7,
"profundidad_maxima": 6,
"kg_iniciales": "2086.00"
}
}
}
🗄️ Base de Datos
Persistencia
- ✅ Los datos persisten entre deploys (volumen Docker
lotes_postgres_data) - ✅ Scripts de inicialización solo se ejecutan si no existen tablas
- ✅ Configuración de autenticación (md5) se aplica automáticamente
Reiniciar BD a Estado Inicial
Para volver a los datos de ejemplo:
# Detener y eliminar volumen
docker compose --project-name lotes down -v
# Próximo deploy reinicializará todo
git commit --allow-empty -m "Trigger redeploy" && git push
Consultas Útiles
-- Ver todos los lotes
SELECT * FROM lotes ORDER BY fecha_creado DESC;
-- Ver trazabilidad completa de un lote
SELECT * FROM get_trazabilidad('id-del-lote');
-- Ver estadísticas de un lote
SELECT * FROM get_estadisticas_lote('id-del-lote');
🎨 Frontend
Tecnologías
- Nuxt 4 - Framework Vue.js
- Nuxt UI - Componentes basados en Tailwind
- TypeScript - Tipado estático
Componentes Principales
- LotesTable - Tabla con filtros y acciones
- LoteForm - Formulario crear/editar lote
- TrazabilidadTree - Árbol de trazabilidad con estadísticas
- OperacionForm - Wizard de 3 pasos para crear operaciones
Modo Debug
El sistema incluye varios botones de debug para desarrollo:
Botones de Prueba de API (azules)
- Abre https://lotes.nucleoriofrio.com
- Abre consola del navegador (F12)
- Usa los botones "Probar GET /api/lotes", "Probar GET /api/operaciones", "Probar Trazabilidad"
- Verifica resultados en consola
⚠️ Botones de Gestión de BD (rojos) - TEMPORALES
ADVERTENCIA: Estos botones son para desarrollo/debugging y están marcados como TEMPORALES.
🗑️ BORRAR TODA LA BD:
- Elimina completamente todas las tablas (
DROP TABLE) - Requiere confirmación antes de ejecutar
- Después de usar, hacer un push para que el workflow recree la BD con datos de ejemplo
🌱 CARGAR DATOS DE EJEMPLO:
- Ejecuta el script de seed (10 lotes, 7 operaciones, 16 relaciones)
- Útil para cargar datos después de un reset
Flujo recomendado para resetear completamente:
# 1. Click en "🗑️ BORRAR TODA LA BD" en la web
# 2. Trigger redeploy para que se recree automáticamente
git commit --allow-empty -m "Trigger reinit DB" && git push
# Alternativa rápida (sin redeploy):
# 1. Click en "🗑️ BORRAR TODA LA BD"
# 2. Click en "🌱 CARGAR DATOS DE EJEMPLO"
# 3. Recargar la página
⚠️ IMPORTANTE: Estos botones y endpoints están marcados con advertencias en el código:
- NO ELIMINAR sin consultar a Dario/Draganel/nucleo000
- Son temporales pero útiles durante desarrollo
- Ver comentarios en el código antes de modificar
🔐 Autenticación
Sistema protegido con Authentik Proxy Outpost:
- Forward Auth: Authentik intercepta todas las peticiones
- Headers automáticos: Usuario inyectado en cada request SSR
- Sin OAuth: No requiere configuración OAuth en la app
- Rutas públicas: PWA assets accesibles sin auth
Ver configuración detallada en la sección de Traefik al final del README.
🛠️ Desarrollo Local
Nota: El desarrollo local tiene limitaciones debido a la dependencia de Authentik Proxy.
Opción 1: Desarrollo con PostgreSQL local
cd nuxt4
npm install
# Configurar PostgreSQL local
export NUXT_POSTGRES_URL=postgres://seguidor:seguidor_password@localhost:5432/seguidor_lotes
# Ejecutar scripts SQL
psql -U seguidor -d seguidor_lotes < server/database/01_schema.sql
psql -U seguidor -d seguidor_lotes < server/database/02_seed.sql
# Iniciar dev server
npm run dev
Opción 2: Desarrollo contra servidor
cd nuxt4
npm install
# Apuntar a BD de producción
export NUXT_POSTGRES_URL=postgres://seguidor:seguidor_password@server.interno.com:5432/seguidor_lotes
npm run dev
📈 Próximos Pasos
Objetivo Actual: Visualización del Grafo
Meta: Mostrar correctamente el grafo de trazabilidad creado con los datos de ejemplo.
Tareas pendientes:
- Componente de visualización de grafo (D3.js, vis.js, o similar)
- Layout de árbol o grafo dirigido
- Interactividad (zoom, pan, click en nodos)
- Mostrar metadatos al hacer hover
- Indicadores visuales de tipos de operación
Mejoras Futuras
- Exportar trazabilidad a PDF
- Búsqueda avanzada de lotes
- Dashboard con estadísticas
- Alertas de mermas excesivas
- Integración con básculas IoT
- App móvil con PWA
- Reportes personalizables
📚 Documentación Adicional
- PLAN_TRAZABILIDAD.md - Plan detallado del sistema
- nuxt4/server/database/README.md - Documentación de BD
- .claude/hooks/README.md - Gitea Actions Hooks
- .claude/CHROME_SETUP.md - Chrome DevTools MCP
🔧 Configuración de Traefik y Authentik
Arquitectura de Autenticación
Usuario → Traefik → Authentik Forward Auth → App Nuxt
↓ (sin sesión)
Redirect a Login
Configuración de Middleware (Traefik)
# dynamic/middlewares.yml
http:
middlewares:
authentik-forward-auth:
forwardAuth:
address: http://authentik-server:9000/outpost.goauthentik.io/auth/traefik
trustForwardHeader: true
authResponseHeaders:
- X-authentik-username
- X-authentik-groups
- X-authentik-email
- X-authentik-name
- X-authentik-uid
Configuración de Proxy Provider (Authentik)
-
Crear Proxy Provider:
- Type:
Forward auth (single application) - External host:
https://lotes.nucleoriofrio.com
- Type:
-
Crear Application:
- Name:
Seguidor de Lotes - Slug:
lotes - Provider: (el creado arriba)
- Name:
-
Vincular a Outpost:
- Agregar la aplicación al Outpost existente
Headers Disponibles en la App
| Header | Descripción |
|---|---|
X-authentik-username |
Nombre de usuario |
X-authentik-email |
|
X-authentik-name |
Nombre completo |
X-authentik-groups |
Grupos (separados por |) |
X-authentik-uid |
ID único |
📄 Licencia
MIT