All checks were successful
build-and-deploy / build-and-deploy (push) Successful in 1m5s
Cambio de 'postgres' a 'lotes-postgres' para evitar errores 28P01 causados por resolución de DNS a instancias incorrectas en la red principal.
406 lines
13 KiB
Markdown
406 lines
13 KiB
Markdown
# 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
|