Implementar sistema completo de trazabilidad de lotes
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s

- Agregar PostgreSQL 16 con esquema completo
- Crear API endpoints para lotes y operaciones
- Implementar UI con Nuxt UI (tablas, formularios, trazabilidad)
- Agregar datos de ejemplo del flujo completo
- Documentar sistema en PLAN_TRAZABILIDAD.md
This commit is contained in:
2025-11-21 18:39:04 -06:00
parent e5456bf522
commit ee3dffa38e
26 changed files with 4223 additions and 74 deletions

501
PLAN_TRAZABILIDAD.md Normal file
View File

@@ -0,0 +1,501 @@
# 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.