# Plan de Trazabilidad de Lotes - Seguidor de Lotes ## Descripción General El **Sistema de Trazabilidad de Lotes** es una aplicación web diseñada para rastrear el flujo completo del café desde el ingreso de uva hasta el secado final. Implementa un **modelo de grafo** que permite representar operaciones complejas como: - **División**: Un lote se divide en varios (ej: despulpado → primera, segunda, rechazos) - **Combinación**: Varios lotes se mezclan en uno (ej: varios reposos → un secado) - **Transformación**: Un lote cambia de estado (ej: oreado → presecado) - **Ajustes**: Correcciones de merma, cantidad o tipo sin alterar el historial --- ## Arquitectura del Sistema ### Stack Tecnológico - **Frontend**: Nuxt 4 + Nuxt UI + Vue 3 - **Backend**: Nuxt Server API Routes - **Base de Datos**: PostgreSQL 16 - **Autenticación**: Authentik Proxy Outpost - **Despliegue**: Docker + Traefik + Gitea Actions ### Estructura del Proyecto ``` /home/draganel/repos/seguidorDeLotes/ ├── nuxt4/ │ ├── app/ │ │ ├── components/ │ │ │ ├── lotes/ │ │ │ │ ├── LotesTable.vue │ │ │ │ ├── LoteForm.vue │ │ │ │ ├── LoteCard.vue │ │ │ │ └── TrazabilidadTree.vue │ │ │ └── operaciones/ │ │ │ ├── OperacionesTable.vue │ │ │ └── OperacionForm.vue │ │ ├── composables/ │ │ │ └── useLotes.ts │ │ └── app.vue │ ├── server/ │ │ ├── api/ │ │ │ ├── lotes/ │ │ │ │ ├── index.get.ts │ │ │ │ ├── index.post.ts │ │ │ │ ├── [id].get.ts │ │ │ │ ├── [id].patch.ts │ │ │ │ ├── [id].delete.ts │ │ │ │ └── [id]/ │ │ │ │ └── trazabilidad.get.ts │ │ │ └── operaciones/ │ │ │ ├── index.get.ts │ │ │ ├── index.post.ts │ │ │ └── [id].get.ts │ │ ├── utils/ │ │ │ ├── db.ts │ │ │ └── queries.ts │ │ └── database/ │ │ ├── 01_schema.sql │ │ ├── 02_seed.sql │ │ └── README.md │ └── package.json ├── docker-compose.yml └── PLAN_TRAZABILIDAD.md (este archivo) ``` --- ## Modelo de Datos ### Concepto Central: Grafo de Lotes y Operaciones El sistema representa la trazabilidad como un **grafo dirigido acíclico (DAG)**: - **Nodos = Lotes**: Estados físicos del café - **Aristas = Operaciones**: Eventos que transforman lotes ### Tablas Principales #### 1. `lotes` Representa cualquier estado físico del café. | Campo | Tipo | Descripción | |-------|------|-------------| | `id` | UUID | Identificador único | | `codigo` | TEXT | Código legible (ej: UVA-001, SEC-042) | | `tipo` | TEXT | Tipo de lote (uva, despulpado_primera, oreado, etc.) | | `fecha_creado` | TIMESTAMPTZ | Fecha de creación | | `lugar_id` | INTEGER | Lugar donde se encuentra (opcional) | | `cantidad_kg` | NUMERIC | Cantidad en kilogramos | | `meta` | JSONB | Datos adicionales (humedad, notas, etc.) | **Tipos de lote válidos:** - `uva` - `despulpado_primera` - `despulpado_segunda` - `despulpado_rechazos` - `oreado` - `presecado` - `reposo` - `secado` #### 2. `operaciones` Representa eventos donde lotes se transforman, combinan o dividen. | Campo | Tipo | Descripción | |-------|------|-------------| | `id` | UUID | Identificador único | | `tipo` | TEXT | Tipo de operación (despulpado, oreado, etc.) | | `fecha` | TIMESTAMPTZ | Fecha de la operación | | `lugar_id` | INTEGER | Lugar donde ocurrió (opcional) | | `meta` | JSONB | Datos adicionales | **Tipos de operación válidos:** *Operaciones de proceso normal:* - `ingreso` - Ingreso de café uva - `despulpado` - Despulpado del café - `oreado` - Proceso de oreado - `presecado` - Presecado - `reposo` - Reposo - `secado` - Secado final - `traslado` - Movimiento de lote - `mezcla` - Mezcla de lotes *Operaciones de ajuste/corrección:* - `ajuste_merma` - Corrección por pérdida de peso - `ajuste_cantidad` - Corrección de cantidad registrada - `ajuste_tipo` - Corrección de tipo de lote - `correccion_asignacion` - Corrección de lote mal asignado - `fusion_manual` - Fusión manual de lotes - `division_manual` - División manual de lotes #### 3. `operacion_lotes` Relación muchos a muchos entre operaciones y lotes. | Campo | Tipo | Descripción | |-------|------|-------------| | `operacion_id` | UUID | ID de la operación | | `lote_id` | UUID | ID del lote | | `rol` | TEXT | 'input' o 'output' | | `cantidad_kg` | NUMERIC | Cantidad específica utilizada/producida | --- ## Diagrama del Grafo de Ejemplo Flujo completo incluido en los datos de ejemplo (`02_seed.sql`): ``` ┌───────────────────────────────┐ │ INGRESO UVA │ │ OP1: ingreso_uva │ └─────────────┬─────────────────┘ │ ▼ [L_UVA1] 2086 kg │ │ ┌─────────────┴──────────────────┐ │ DESPULPADO │ │ OP2: despulpado │ └───┬─────────┬─────────┬────────┘ │ │ │ ▼ ▼ ▼ [L_PRIM1] [L_SEG1] [L_RECH1] 1500 kg 400 kg 150 kg │ │ ┌────────────┴───────────────────────────┐ │ OREADO │ │ OP3: oreado (registro mal) │ └─────────────────────┬───────────────────┘ │ ▼ [L_ORE1] 1500 kg │ │ ┌────────────────────────┴────────────────────────────┐ │ AJUSTE DE MERMA │ │ OP4: ajuste_merma (1500 → 1480 kg) │ └───────────────────────────┬──────────────────────────┘ │ ▼ [L_ORE1A] 1480 kg │ │ ┌───────────────────────┴───────────────────────────┐ │ AJUSTE DE TIPO │ │ OP5: ajuste_tipo (oreado → presecado) │ └──────────────────────────┬─────────────────────────┘ │ ▼ [L_PRE1] 1480 kg │ │ ┌────────────────────┴────────────────────────┐ │ REPOSO │ │ OP6: reposo │ └───────────────────┬──────────────────────────┘ │ ▼ [L_REP1] 1480 kg │ │ (+ [L_REP2] 520 kg) │ │ ┌──────────────────────────┴──────┴────────────────────┐ │ SECADO │ │ OP7: secado (mezcla) │ └───────────────────────┬───────────────────────────────┘ │ ▼ [L_SEC1] 2000 kg ``` --- ## Ejemplos de Uso de la API ### 1. Listar todos los lotes ```bash GET /api/lotes # Con filtros GET /api/lotes?tipo=secado&limit=10 ``` **Respuesta:** ```json { "success": true, "data": [ { "id": "uuid-here", "codigo": "SEC-001", "tipo": "secado", "fecha_creado": "2025-11-21T10:00:00Z", "cantidad_kg": 2000, "meta": { "humedad_final": 11.5 } } ], "count": 1 } ``` ### 2. Obtener trazabilidad completa de un lote ```bash GET /api/lotes/{id}/trazabilidad ``` **Respuesta:** ```json { "success": true, "data": { "historial": [ { "lote_id": "uuid-sec-001", "codigo": "SEC-001", "tipo": "secado", "cantidad_kg": 2000, "operacion_id": "uuid-op-secado", "operacion_tipo": "secado", "profundidad": 0 }, { "lote_id": "uuid-rep-001", "codigo": "REP-001", "tipo": "reposo", "cantidad_kg": 1480, "operacion_id": "uuid-op-reposo", "operacion_tipo": "reposo", "profundidad": 1 } // ... más ancestros ], "estadisticas": { "total_ancestros": 7, "profundidad_maxima": 6, "kg_iniciales": 2086 } } } ``` ### 3. Crear una nueva operación (ejemplo: despulpado) ```bash POST /api/operaciones Content-Type: application/json { "tipo": "despulpado", "inputs": [ { "lote_id": "uuid-uva-001", "cantidad_kg": 2086 } ], "outputs": [ { "codigo": "PRIM-001", "tipo": "despulpado_primera", "cantidad_kg": 1500 }, { "codigo": "SEG-001", "tipo": "despulpado_segunda", "cantidad_kg": 400 }, { "codigo": "RECH-001", "tipo": "despulpado_rechazos", "cantidad_kg": 150 } ], "meta": { "pila": 2, "operador": "Juan Pérez" } } ``` **Respuesta:** ```json { "success": true, "data": { "operacion": { "id": "uuid-operacion", "tipo": "despulpado", "fecha": "2025-11-21T10:00:00Z", "meta": { "pila": 2, "operador": "Juan Pérez" } }, "lotes_creados": [ { "id": "uuid-prim", "codigo": "PRIM-001", "tipo": "despulpado_primera" }, { "id": "uuid-seg", "codigo": "SEG-001", "tipo": "despulpado_segunda" }, { "id": "uuid-rech", "codigo": "RECH-001", "tipo": "despulpado_rechazos" } ] } } ``` --- ## Componentes Frontend ### Componentes de Lotes 1. **LotesTable.vue** - Tabla con listado de lotes - Filtros por tipo - Acciones: Ver, Editar, Ver Trazabilidad 2. **LoteForm.vue** - Formulario para crear/editar lotes - Validación de campos - Soporte para metadata JSON 3. **LoteCard.vue** - Vista de detalle de un lote - Información completa del lote - Acciones rápidas 4. **TrazabilidadTree.vue** - Visualización del historial completo - Árbol indentado por profundidad - Estadísticas de trazabilidad ### Componentes de Operaciones 1. **OperacionesTable.vue** - Tabla con listado de operaciones - Filtros por tipo - Acciones: Ver detalle 2. **OperacionForm.vue** - Formulario multi-paso: 1. Seleccionar tipo de operación 2. Seleccionar lotes input 3. Definir lotes output - Creación transaccional --- ## Consultas SQL Importantes ### Obtener trazabilidad completa (función recursiva) ```sql SELECT * FROM get_trazabilidad('uuid-del-lote-final'); ``` Esta función CTE recursiva camina el grafo hacia atrás desde el lote final hasta los ingresos iniciales. ### Ver lotes con su operación de origen ```sql SELECT * FROM vista_lotes_con_origen ORDER BY fecha_creado DESC; ``` --- ## Despliegue ### Requisitos - Docker y Docker Compose - Acceso al servidor con Traefik y Authentik configurados - Gitea con Actions habilitado ### Variables de Entorno ```env # PostgreSQL POSTGRES_USER=seguidor POSTGRES_PASSWORD=seguidor_password POSTGRES_DB=seguidor_lotes # Aplicación APP_NAME=seguidorDeLotes APP_DOMAIN=lotes.nucleoriofrio.com NUXT_PUBLIC_APP_URL=https://lotes.nucleoriofrio.com # Registry REG=gitea.nucleoriofrio.com REPO_OWNER=nucleo000 ``` ### Proceso de Deploy 1. **Push a main/master** → Gitea Actions se ejecuta automáticamente 2. **Build**: Construye imagen Docker 3. **Push**: Sube imagen al registry de Gitea 4. **Deploy**: Ejecuta `docker-compose up -d` en el servidor ### Primer Inicio Al iniciar PostgreSQL por primera vez, ejecutará automáticamente: 1. `01_schema.sql` - Crea tablas, índices, funciones 2. `02_seed.sql` - Inserta datos de ejemplo --- ## Próximos Pasos ### Fase 2: Visualización Avanzada - [ ] Integrar librería de grafos (Cytoscape.js o D3.js) - [ ] Vista de grafo interactivo - [ ] Zoom, pan y selección de nodos - [ ] Colores por tipo de lote ### Fase 3: Reportes y Análisis - [ ] Reporte de trazabilidad en PDF - [ ] Estadísticas por período - [ ] Gráficos de volumen procesado - [ ] Análisis de mermas ### Fase 4: Características Avanzadas - [ ] Gestión de lugares (patios, pilas, bodegas) - [ ] QR codes para lotes - [ ] Escáner móvil - [ ] Notificaciones de eventos - [ ] Integración con básculas --- ## Troubleshooting ### La base de datos no se inicializa Verificar logs del contenedor postgres: ```bash docker logs seguidorDeLotes-postgres ``` ### Los datos de ejemplo no se cargan Eliminar el volumen y recrear: ```bash docker-compose down -v docker-compose up -d ``` ### Error de conexión a PostgreSQL Verificar que el contenedor postgres esté saludable: ```bash docker ps # Buscar "healthy" en la columna STATUS ``` --- ## Contacto y Soporte - **Proyecto**: Nucleo Rio Frio - **Desarrollador**: Dario (draganel) - **Repositorio**: https://gitea.nucleoriofrio.com/nucleo000/seguidorDeLotes --- ## Licencia Este proyecto es propiedad de **Nucleo Rio Frio** y está desarrollado para uso interno.