# 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 1. **Fork/Clone del repositorio** en tu Gitea 2. **Configurar variables en Gitea** (`Settings > Actions`): **Secrets:** - `REGISTRY_USERNAME` - Usuario del registro Docker - `REGISTRY_PASSWORD` - Contraseña del registro - `POSTGRES_PASSWORD` - Contraseña de PostgreSQL **Variables:** - `REGISTRY_URL` - `gitea.nucleoriofrio.com` - `APP_NAME` - `lotes` - `APP_DOMAIN` - `lotes.nucleoriofrio.com` - `NUXT_PUBLIC_APP_URL` - `https://lotes.nucleoriofrio.com` - `POSTGRES_USER` - `seguidor` - `POSTGRES_DB` - `seguidor_lotes` 3. **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 │ ├── server/ │ │ ├── api/ │ │ │ ├── lotes/ # Endpoints de lotes (6) │ │ │ └── operaciones/ # Endpoints de operaciones (3) │ │ ├── utils/ │ │ │ ├── db.ts # Pool de PostgreSQL │ │ │ └── queries.ts # Funciones SQL │ │ └── database/ │ │ ├── 00_configure_auth.sh # Config autenticación │ │ ├── 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 lote - `GET /api/lotes/:id` - Obtener lote específico - `PATCH /api/lotes/:id` - Actualizar lote - `DELETE /api/lotes/:id` - Eliminar lote - `GET /api/lotes/:id/trazabilidad` - Obtener trazabilidad completa ### Operaciones - `GET /api/operaciones` - Listar operaciones - `POST /api/operaciones` - Crear operación con lotes - `GET /api/operaciones/:id` - Obtener operación específica ### Ejemplo de Respuesta - Trazabilidad ```json { "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: ```bash # 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 ```sql -- 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 botones de prueba para verificar la API: 1. Abre https://lotes.nucleoriofrio.com 2. Abre consola del navegador (F12) 3. Usa los botones "Probar API" 4. Verifica resultados en consola ## 🔐 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 ```bash cd nuxt4 npm install # Configurar PostgreSQL local export POSTGRES_USER=seguidor export POSTGRES_PASSWORD=seguidor_password export POSTGRES_DB=seguidor_lotes export POSTGRES_HOST=localhost # 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 ```bash cd nuxt4 npm install # Apuntar a BD de producción export POSTGRES_HOST=server.interno.com export POSTGRES_PORT=5432 # ... resto de variables 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_TRAZABILIDAD.md) - Plan detallado del sistema - [nuxt4/server/database/README.md](nuxt4/server/database/README.md) - Documentación de BD - [.claude/hooks/README.md](.claude/hooks/README.md) - Gitea Actions Hooks - [.claude/CHROME_SETUP.md](.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) ```yaml # 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) 1. **Crear Proxy Provider**: - Type: `Forward auth (single application)` - External host: `https://lotes.nucleoriofrio.com` 2. **Crear Application**: - Name: `Seguidor de Lotes` - Slug: `lotes` - Provider: (el creado arriba) 3. **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` | Email | | `X-authentik-name` | Nombre completo | | `X-authentik-groups` | Grupos (separados por `\|`) | | `X-authentik-uid` | ID único | ## 📄 Licencia MIT