# Plan de Trazabilidad de Lotes - Seguidor de Lotes

## Estado Actual del Proyecto

🌐 **Producción**: https://lotes.nucleoriofrio.com

### ✅ Completado

- [x] Modelo de base de datos (grafo DAG)
- [x] Scripts de inicialización y seed con datos de ejemplo
- [x] API REST completa (11 endpoints + 2 debug temporales)
- [x] Función recursiva de trazabilidad SQL
- [x] Autenticación con Authentik Proxy
- [x] CI/CD con Gitea Actions
- [x] Despliegue automático con Docker Compose
- [x] Persistencia de datos entre deploys
- [x] Configuración automática de autenticación PostgreSQL
- [x] Botones de prueba de API en frontend
- [x] **Botones de debug temporales** para gestión de BD (reset y seed)
  - ⚠️ Marcados como TEMPORALES - NO ELIMINAR sin consultar
  - `POST /api/debug/reset-database` - DROP de todas las tablas
  - `POST /api/debug/seed-database` - Carga datos de ejemplo
  - UI con advertencias notorias en rojo

### 🎯 Objetivo Actual: Visualización del Grafo

**Meta**: Implementar un componente visual que muestre el grafo de trazabilidad de forma interactiva.

**Requisitos**:
- Visualizar el flujo completo de un lote desde origen hasta estado actual
- Mostrar nodos (lotes) y aristas (operaciones)
- Interactividad: zoom, pan, click en nodos
- Metadatos al hacer hover
- Indicadores visuales por tipo de operación

**Tecnologías a considerar**:
- D3.js (máximo control, curva de aprendizaje)
- vis.js (redes y grafos, fácil de usar)
- Cytoscape.js (grafos complejos, buena performance)
- ELK.js (layout automático de grafos)

---

## Descripción General

El **Sistema de Trazabilidad de Lotes** rastrea el flujo completo del café desde el ingreso de uva hasta el secado final. Implementa un **modelo de grafo (DAG)** que permite representar operaciones complejas:

- **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]/
│   │   │   ├── debug/                      # ⚠️ TEMPORALES
│   │   │   │   ├── reset-database.post.ts
│   │   │   │   └── seed-database.post.ts
│   │   │   │       └── 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" }
    ]
  }
}
```

### 4. Endpoints de Debug (⚠️ Temporales)

**⚠️ ADVERTENCIA**: Estos endpoints son temporales y están marcados para no eliminar sin consultar.

#### Reset Database

```bash
POST /api/debug/reset-database
```

**Descripción**: Elimina completamente todas las tablas (DROP TABLE) para reinicializar la BD.

**Respuesta:**
```json
{
  "success": true,
  "message": "Base de datos reseteada. Tablas eliminadas completamente. El próximo deploy las recreará con datos de ejemplo."
}
```

**Flujo recomendado:**
1. Llamar a este endpoint desde el frontend (botón rojo)
2. Hacer push para triggear workflow
3. El workflow detecta que no hay tablas y las recrea con seed

#### Seed Database

```bash
POST /api/debug/seed-database
```

**Descripción**: Ejecuta el script de seed (`02_seed.sql`) para cargar datos de ejemplo.

**Respuesta:**
```json
{
  "success": true,
  "message": "Datos de ejemplo cargados: 10 lotes, 7 operaciones, 16 relaciones"
}
```

**Uso típico:**
- Después de resetear la BD manualmente
- Para pruebas de desarrollo
- Para restaurar datos de ejemplo rápidamente

**⚠️ Nota importante**: Estos endpoints incluyen comentarios muy visibles en el código fuente:
```typescript
/**
 * ⚠️ ⚠️ ⚠️ ENDPOINT DE DEBUG - TEMPORAL ⚠️ ⚠️ ⚠️
 *
 * ⚠️ NO ELIMINAR SIN CONSULTAR A DARIO/DRAGANEL/NUCLEO000 ⚠️
 */
```

---

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