Portfolio · Full-stack · Open Source
💼 LinkedIn ✉️ Email

Proyecto destacado · Product Engineering · Full Stack

KAVANA Steelworks - MES para bobinas de acero nacido desde la metalurgia

Proyecto portfolio de full-stack. Construí un MES/MOM especializado en la transformación de bobinas de acero: el motor FIFO que decide qué bobina se consume primero, la reconciliación industrial que cuadra los kilos con la báscula, el coste real por lote y la trazabilidad ISO 9001. Todo lo que viví en 8 años en el sector metalúrgico, traducido a arquitectura.

Tecnologías: Python, FastAPI, PostgreSQL, React + TypeScript, WebSockets, Alembic, Docker, GitHub Actions. Ver arquitectura completa →

304+
Tests (233+ backend + 71 frontend)
24
Tablas PostgreSQL
5
ADRs documentados
FIFO
Motor de bobinas
📐 Decisiones técnicas 🏭 ADR: MES/MOM 🗄️ ADR: PostgreSQL 🔌 ADR: WebSockets planta 🏢 ADR: Admin multi-tenant 📋 Ver los 5 ADRs
El origen

Por qué construí esto

Pasé 8 años en varias fábricas del sector metalúrgico (máquinas CNC, turnos de mañana, tarde y noche, bobinas de acero de cientos de kilos). Sé lo que pesa una bobina, cómo se miden los milímetros de radio que quedan en el mandril y por qué un operario no quiere teclear datos a mano con los guantes puestos.

El problema real en planta: cada bobina entra con su etiqueta (peso, lote, dimensiones), el operario gasta varias bobinas por turno y al final nadie sabe exactamente cuántos kilos se consumieron de verdad, cuánto se desperdició y qué costó cada pieza. Los ERPs generalistas son complejos para el operario y no hablan el idioma de la fábrica: bobinas, picos, retales, reconciliación con báscula.

Kavana Steelworks no nació de un ejercicio de programación. Nació de lo que vi durante años: cómo se pierde material, cómo el coste real no cuadra con el estimado y cómo los operarios acaban apuntando en papel porque el software no entiende su trabajo. Este proyecto demuestra cómo traduje esa experiencia en arquitectura: un motor FIFO de bobinas, reconciliación con la báscula y una interfaz que no abruma al operario.

Lo que demuestra

Capacidades técnicas visibles en este proyecto

🏗️

Backend Python real

FastAPI modular (core, models, services, routers) con SQLAlchemy 2.0, Alembic y 24 tablas PostgreSQL aplicadas en base real. API OpenAPI documentada con /docs.

🔗

Motor FIFO de bobinas

Cascada FIFO por fecha de entrada con burbuja de vinculación: las bobinas fantasma de otros turnos no se consumen por error. Herencia entre bobinas, JIT Move y tolerancia de superávit (max(15%, 150kg)). El corazón del sistema, portado del legacy con 10 tests.

⚖️

Reconciliación industrial

Los kilos cuadran con la báscula: coste real por lote (no precio medio), retales medidos en milímetros de radio, y merma oculta calculada entre lo que el sistema cree y lo que pesa de verdad. Números de kilos y dinero con constraints en la BD.

🚩

Feature flags por plan

12 features activables por tenant (básico/pro/industrial): auto-vinculación de bobinas, burbuja FIFO, coste real, trazabilidad completa. Cada planta usa solo lo que necesita, mismo código. Patrón probado en el ecosistema Kavana.

🧪

297 tests con TDD estricto

226 pytest (motor FIFO, recepción, auth, producción, OEE, calidad, incidencias, trazabilidad) + 71 vitest (flujo escaneo, producción, supervisor, admin). TDD rojo-verde contra el contrato de las specs, y CI en GitHub Actions que ejecuta la suite en cada push.

🧤

UX que no abruma al operario

Directriz de diseño: mantener la esencia brutalista industrial pero simplificar para que el operario no se sienta abrumado. Una acción principal a la vez, datos de apoyo colapsados, guía de acción visible y sugerencias de picos que aconsejan sin imponer.

🗄️

PostgreSQL con migraciones

SQLAlchemy 2.0 + Alembic versionado, aplicado y verificado contra PostgreSQL real (24 tablas). Constraints y CHECKs para que kilos y dinero cuadren: el sistema no puede inventarse el stock.

📊

OEE y coste por orden en vivo

OEE = A×P×Q calculado con datos reales de la BD (disponibilidad, rendimiento, calidad), sin datos muestra 0, nunca inventa valores. KPIs financieros: coste real vs estimado, varianzas, eficiencia y tasa de merma.

🚫

Validación de material por características

La orden declara el material que gasta el modelo; al vincular una bobina el sistema bloquea la incompatible: otro tipo de material, ancho fuera de ±2 mm o espesor fuera de ±10 %. Mensaje claro al operario, sin dejar pasar errores.

🐳

Desplegado en producción

Backend en Fly.io con PostgreSQL gestionado (migraciones + seed demo en el entrypoint) y frontend en Vercel con rewrites /api/*. CI verde en cada push: ruff + pytest + migraciones + build TS + vitest.

📋

5 ADRs + 9 specs del dominio

Clasificación MES/MOM (ISA-95), PostgreSQL sobre MongoDB, feature flags por plan, WebSockets de planta y administración multi-tenant. Y 9 specs que documentan el contrato de comportamiento extraído del legacy, incluyendo el flujo real del operario. Ver ADRs →

Decisiones técnicas

Criterio aplicado, no solo código

Más allá de las tecnologías, aquí hay decisiones de arquitectura que nacen del producto, no de la tecnología. Cada una responde a un requisito real de planta y tiene su ADR.

🏭 MES/MOM, no ERP

El sistema se clasifica como MES con alcance MOM según ISA-95: cubre las cuatro operaciones (producción, calidad, mantenimiento, inventario) más la reconciliación industrial. No intenta ser un ERP: no factura ni gestiona RRHH. ADR →

🗄️ PostgreSQL sobre MongoDB

El dominio es altamente relacional: órdenes, bobinas, consumos y stock se cruzan constantemente. El FIFO necesita transacciones atómicas (consumir bobina + decrementar stock + Kardex en una sola operación) y constraints para que kilos y dinero cuadren con la báscula. ADR →

🧤 UX brutalista pero sin abrumar

Esencia visual industrial (brutalismo, naranja, monoespaciada para datos físicos) pero con jerarquía clara: una acción principal a la vez, datos de apoyo colapsados y sugerencias que aconsejan sin imponer. La funcionalidad nunca se elimina, solo se reorganiza.

🚩 Feature flags por plan

Cada planta tiene un nivel de automatización distinto: básico (manual), pro (auto-vinculación y burbuja FIFO) o industrial (trazabilidad completa). Mismo código, features activables por tenant, patrón replicado del ecosistema Kavana. ADR →

🧪 TDD contra specs, no contra el aire

Las specs extraídas del legacy definen el contrato (FIFO con burbuja, JIT Move, Kardex, guard de seguridad). Cada servicio se escribe con tests rojos primero y CI ejecuta la suite en cada push. El portado no pierde lógica por el camino.

📋 Historia documentada por fases

Changelog con narrativa por fase, spec del flujo real del operario y decisiones con su porqué. El repositorio cuenta la historia completa: por qué se construye, qué se portó del legacy y qué se descartó. DECISIONS.md

Stack tecnológico

Arquitectura real, no mockups

🔙 Backend

Python 3.12FastAPISQLAlchemy 2.0PostgreSQLAlembicPydanticJWT (8h)pytestuv
  • Motor FIFO de bobinas con burbuja de vinculación
  • Recepción de materiales con Kardex (GRN)
  • Auth JWT de 8 horas (un turno) con revocación
  • Broker de eventos de planta por tenant

🎨 Frontend

React 19TypeScriptViteTailwind v4React RouterTanStack QueryPWAVitest
  • Design system KAVANA (brutalismo industrial)
  • Paneles: Operario, Materias Primas, Supervisor
  • Directriz UX: no abrumar al operario
  • PWA offline-first con service worker

🏗️ Infraestructura

GitHub ActionsuvDockerPostgreSQL realFly.io
📚 README completo · DECISIONS.md · ADRs (5 documentos) · Repositorio
El flujo completo

Cómo circula una bobina en planta

Materias Primas (recepción) │ pesa la bobina · material · dimensiones · lote · heat ▼ API FastAPI (receive_coil) │ GRN en Kardex · stock padre · evento de planta ▼ PostgreSQL (24 tablas, constraints de kg/dinero) │ ▼ Operario (escanea la etiqueta QR) │ vincula la bobina a su orden ▼ Motor FIFO (burbuja de vinculación) │ consume kg por fecha de entrada · JIT Move · retales ▼ Oficina (supervisor) OEE por turno · coste real vs estimado · alertas de almacén
Estado real

Qué está hecho (verificable) y qué no

Transparencia total: cada punto se puede verificar en el repositorio público. No hay clientes en producción.

Implementado y verificable en repo

Motor FIFO de bobinas completo (burbuja, JIT Move, Kardex, 10 tests)
Backend FastAPI: recepción, auth JWT 8h con roles, feature flags, eventos
24 tablas PostgreSQL con migraciones Alembic aplicadas
297 tests (226 pytest + 71 vitest) con CI en GitHub Actions
5 ADRs + 9 specs del dominio + flujo real del operario
Frontend React + TS con login por roles y design system
E2E verificado contra PostgreSQL real (escaneo, producción, fin de bobina, OEE, validación de material)
Fin de bobina (radio en mm → kg) + botón Retirar + picos como sugerencia
Producción con auto-consumo FIFO y panel Supervisor con OEE/KPIs reales
Validación de material por características (ancho, espesor, tipo) al vincular
Desplegado en Fly.io (PostgreSQL gestionado) + Vercel con demo pública
Trazabilidad ISO 9001 completa: ProductionLog inmutable + triggers y UI en Supervisor
WebSockets de planta (ADR-014) con fallback a polling
Autocontroles de calidad e incidencias de planta con foto desde el móvil (QR)
Administración multi-tenant: usuarios, secuencias, puestos y roles (Fase 7)
Recordatorios de autocontrol en el panel del operario (15 min / 2 h)

🚧 Planificado (no implementado)

🚧 Capturas reales de la demo y post de LinkedIn (Fase 5)

El proyecto está vivo. Cada semana avanzo en los módulos planificados. El repo refleja el estado real en cada commit.

Demo en vivo

Estado del despliegue

🏭 Kavana Steelworks

Demo pública desplegada: backend en Fly.io con PostgreSQL real (migraciones + datos demo automáticos) y frontend en Vercel. Datos ficticios de demostración, sin clientes reales. Escanea la bobina demo COIL-DEMO-001 en el panel de Operario.

💡 Cómo probarla
Bobina demo: COIL-DEMO-001 (800 kg, decapado 1.2×1220)
Orden demo: OP-DEMO-001 (objetivo 50 piezas)
Paneles: Operario (escanea y produce) · Materias Primas · Supervisor (OEE y KPIs)
Login demo: operario@demo.local / kavana (supervisor@demo.local, materias@demo.local, admin@demo.local)
Abrir la demo →

💻 Código completo

Repositorio público con docker-compose: levanta PostgreSQL, Redis, backend y frontend en local con un comando.

Ver en GitHub →

¿Quieres ver más?

Este es uno de los proyectos de mi portfolio. Si quieres ver el código, las decisiones técnicas documentadas, o simplemente conectar: