Files
seguidorDeLotes/PLAN_TRAZABILIDAD.md
josedario87 ee3dffa38e
Some checks failed
build-and-deploy / build-and-deploy (push) Failing after 1m47s
Implementar sistema completo de trazabilidad de lotes
- 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
2025-11-21 18:39:04 -06:00

15 KiB

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

GET /api/lotes

# Con filtros
GET /api/lotes?tipo=secado&limit=10

Respuesta:

{
  "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

GET /api/lotes/{id}/trazabilidad

Respuesta:

{
  "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)

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:

{
  "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)

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

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

# 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:

docker logs seguidorDeLotes-postgres

Los datos de ejemplo no se cargan

Eliminar el volumen y recrear:

docker-compose down -v
docker-compose up -d

Error de conexión a PostgreSQL

Verificar que el contenedor postgres esté saludable:

docker ps
# Buscar "healthy" en la columna STATUS

Contacto y Soporte


Licencia

Este proyecto es propiedad de Nucleo Rio Frio y está desarrollado para uso interno.