# 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`
   - `NUXT_POSTGRES_URL` - `postgres://seguidor:seguidor_password@lotes-postgres:5432/seguidor_lotes`
   - `POSTGRES_USER` - `seguidor`
   - `POSTGRES_DB` - `seguidor_lotes`
   - `POSTGRES_PORT` - `5432`

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 (con botones debug)
│   ├── server/
│   │   ├── api/
│   │   │   ├── lotes/          # Endpoints de lotes (6)
│   │   │   ├── operaciones/    # Endpoints de operaciones (3)
│   │   │   └── debug/          # ⚠️ Endpoints debug temporales (2)
│   │   ├── utils/
│   │   │   ├── db.ts           # Pool de PostgreSQL
│   │   │   └── queries.ts      # Funciones SQL
│   │   └── database/
│   │       ├── 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

### Debug (⚠️ Temporales)

- `POST /api/debug/reset-database` - Elimina todas las tablas (DROP)
- `POST /api/debug/seed-database` - Carga datos de ejemplo

**Nota**: Estos endpoints están marcados como temporales. No eliminar sin consultar.

### 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 varios botones de debug para desarrollo:

#### Botones de Prueba de API (azules)

1. Abre https://lotes.nucleoriofrio.com
2. Abre consola del navegador (F12)
3. Usa los botones "Probar GET /api/lotes", "Probar GET /api/operaciones", "Probar Trazabilidad"
4. Verifica resultados en consola

#### ⚠️ Botones de Gestión de BD (rojos) - TEMPORALES

**ADVERTENCIA**: Estos botones son para desarrollo/debugging y están marcados como **TEMPORALES**.

**🗑️ BORRAR TODA LA BD**:
- Elimina completamente todas las tablas (`DROP TABLE`)
- Requiere confirmación antes de ejecutar
- Después de usar, hacer un push para que el workflow recree la BD con datos de ejemplo

**🌱 CARGAR DATOS DE EJEMPLO**:
- Ejecuta el script de seed (10 lotes, 7 operaciones, 16 relaciones)
- Útil para cargar datos después de un reset

**Flujo recomendado para resetear completamente**:
```bash
# 1. Click en "🗑️ BORRAR TODA LA BD" en la web
# 2. Trigger redeploy para que se recree automáticamente
git commit --allow-empty -m "Trigger reinit DB" && git push

# Alternativa rápida (sin redeploy):
# 1. Click en "🗑️ BORRAR TODA LA BD"
# 2. Click en "🌱 CARGAR DATOS DE EJEMPLO"
# 3. Recargar la página
```

**⚠️ IMPORTANTE**: Estos botones y endpoints están marcados con advertencias en el código:
- NO ELIMINAR sin consultar a Dario/Draganel/nucleo000
- Son temporales pero útiles durante desarrollo
- Ver comentarios en el código antes de modificar

## 🔐 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 NUXT_POSTGRES_URL=postgres://seguidor:seguidor_password@localhost:5432/seguidor_lotes

# 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 NUXT_POSTGRES_URL=postgres://seguidor:seguidor_password@server.interno.com:5432/seguidor_lotes

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
