Saltar al contenido principalSaltar a la navegación principalSaltar al pie de página
JZdev
ProyectosBlogContacto
es/en
es/en
JZ
Menú de navegación
ProyectosBlogContacto
JZ

Backend Developer especializado en sistemas end-to-end con Java, Go y Rust — soluciones robustas, escalables y mantenibles.

Contactar →

Navegación

  • Proyectos
  • Blog
  • Contacto
© 2026 Javier Zader. Hecho cony mucho mate 🧉
PrivacidadDatos GDPRConstruido con Next.js
Inicio/Proyectos/Biogas Platform
Volver a proyectos
CuradoDestacado

Biogas Platform

Plataforma industrial para plantas de biogás en producción: ingesta de telemetría en tiempo real por MQTT, detección de anomalías en tres capas (edge en Rust + ONNX, ensemble en la nube) y multi-tenancy con row-level security real en Postgres.

Descripción del Proyecto

Las alarmas por umbral fijo son fáciles de escribir y malas para detectar deterioro gradual: cuando un sensor cruza el límite, la condición que lo llevó ahí ya lleva rato. Esta plataforma monitorea plantas de biogás en producción, ingiere su telemetría en tiempo real por MQTT, y apunta a esa brecha —la deriva que un umbral no ve.

La detección corre en dos lugares a propósito. En el edge, cerca del sensor, un Z-score y un IsolationForest exportado a ONNX marcan anomalías al instante, sin depender de la red. En la nube, un ensemble más pesado (IsolationForest + LSTM Autoencoder) cruza el histórico que el edge no tiene. Si un modelo del edge no está cargado, esa capa cae a la anterior en vez de cortar la ingesta.

La plataforma corre varias plantas, de distintos operadores, sobre la misma base de datos, así que el aislamiento no podía depender de acordarse de filtrar. Es row-level security real en Postgres, con el rol de la aplicación creado bajo NOBYPASSRLS: no puede saltear el aislamiento aunque una query se olvide del WHERE. El tenant se fija por sesión, no por convención.

De un vistazo#

  • ~580.000 líneas entre Go, Rust, Python y TypeScript
  • 124 tablas bajo RLS: 239 políticas, rol de aplicación bajo NOBYPASSRLS
  • 6.528 tests, con suite de integración contra Postgres real
  • 2.656 commits, 67 merge requests en ~5 meses; en producción
Loading diagram...
Topología edge→cloud: el gateway Rust opera local (offline-first) y sincroniza con el backend cuando hay link; los sensores también entran por MQTT.

Las restricciones que me puse#

  • El edge tiene que funcionar sin internet. Las plantas pueden perder conectividad por horas; las operaciones y la detección de anomalías tienen que seguir corriendo localmente.
  • Los modelos son activos de producción versionados. Nada de drops de modelos ad-hoc — cada modelo se entrena, se valida, se empaqueta como ONNX, se versiona en almacenamiento compatible con S3, y se despliega por un rollout controlado.
  • Specs-driven desde el día uno. OpenSpec es la fuente de verdad para los contratos entre apps; ninguna API "se shippea nomás" sin una spec primero.
  • Consciente de roles desde el arranque. Operarios de planta, personal técnico, supervisores y dueños ven vistas distintas y tienen capacidades distintas — el modelo de roles es parte de la capa de datos, no un agregado de la UI.

Mi rol#

Desarrollador único. Arrancó el 9 de febrero de 2026. Mi sobrino, ingeniero ambiental, es el experto de dominio que valida que el producto coincida con cómo operan las plantas de verdad. Yo me hice cargo de cada decisión técnica del stack:

  • La estructura del monorepo — qué es una app, qué es un paquete compartido, qué es un servicio, y dónde caen los límites.
  • La capa de contratos — OpenSpec como fuente de verdad entre apps antes de que se escriba una línea de código.
  • El diseño del edge gateway en Rust — integración del protocolo Modbus, store SQLite offline-first con cola de sync, la disposición del subsistema de IA (agentes, clasificador, registro de modelos, LLM local), actualizaciones de modelos por OTA con artefactos firmados.
  • La arquitectura de ML de tres capas — qué corre en el edge, qué corre en la nube, qué se entrena en batch, qué infiere en tiempo real, y cómo se mueven los modelos entre ellas.
  • El modelo de roles — operarios, personal técnico, supervisores, dueños — como un concepto de la capa de datos, no un toggle de la UI.
  • El plugin de Biome propio (eslint-plugin-biogas-ssot) que hace cumplir las convenciones de fuente-única-de-verdad entre apps en tiempo de lint.
  • El pipeline de CI/CD en GitLab — versionado de modelos a almacenamiento compatible con S3, tests de paridad como gate de despliegue, rollouts controlados.

Cómo empezó Biogas Platform, y por qué creció#

Empezó como una conversación: mi sobrino describió la realidad del Excel, yo describí la plataforma que debería reemplazarlo. La primera versión era modesta — un backend en Go, una base Postgres, un dashboard básico. Ingerir el dato de los sensores, mostrarlo en un gráfico, reemplazar el registro diario.

Una vez que el loop básico funcionó, las preguntas se apilaron. Si el dato está en una base de datos de verdad, ¿por qué no detectar anomalías automáticamente? Si detectamos anomalías, ¿por qué no predecir fallos? Si predecimos fallos, ¿por qué no correr la inferencia en la planta para que funcione offline? Si la corremos en la planta, ¿cómo actualizamos los modelos de forma segura? Cada respuesta sumó una capa, y la plataforma creció hasta lo que es hoy.

Decisiones clave#

1. Edge gateway en Rust como nodo industrial autosuficiente#

El edge gateway es el corazón del sistema, no un wrapper delgado de inferencia. Es el componente que la planta corre localmente, y tiene que seguir funcionando cuando todo lo demás no está disponible — el enlace WAN, el backend en la nube, el registro de modelos. Por eso es la aplicación individual más grande de la plataforma: 74 archivos fuente en Rust, 18 subsistemas, versión 2.1.0, diseñado como un nodo industrial autónomo que, cuando puede, sincroniza con la nube.

Lo que el gateway hace realmente en la planta:

  • Habla con los PLCs por Modbus TCP/RTU — el protocolo industrial que los sensores y controladores realmente hablan. Registros holding, input, coils y discrete-input, con escala, offset y tipos de dato configurables (u16/i16/f32).
  • Persiste cada lectura en un store SQLite local con una cola de sync, así una caída del enlace de salida solo demora la sincronización — nunca pierde dato. El sync es HTTP por lotes con reintento exponencial, circuit breaker y tamaños de lote configurables.
  • Corre inferencia de ML localmente vía onnxruntime 2.0 (el crate ort) — detección de anomalías en cada lectura sin una ida y vuelta a la nube.
  • Aloja un subsistema de IA local con modelos de lenguaje on-device (llama_cpp), clasificador, correlador, y un registro de modelos con selección consciente del hardware — elige el tamaño de modelo correcto para el gateway en el que está corriendo.
  • Tiene un framework de agentes de IA: agente de ayuda, agente de consultas SQLite, agente de estado — agentes chicos y especializados con los que un operario puede hablar desde el dashboard de la planta sin ninguna conexión a la nube.
  • Soporta actualizaciones OTA (over-the-air) con artefactos de modelo firmados con ed25519 — los modelos se descargan, se verifica su firma, y se despliegan sin reiniciar el gateway.
  • Expone métricas Prometheus en :9090/metrics y health checks en :8888/health para el monitoreo; trae su propia PWA de dashboard embebida para que un operario pueda inspeccionar el estado sin una herramienta externa.

Por qué Rust: un proceso que corre desatendido en el hardware de la planta durante semanas seguidas, haciendo IO en tiempo real con protocolos industriales e inferencia de ML, no puede permitirse memory leaks, pausas de GC, ni panics no manejados que tumben el gateway. Rust da rendimiento predecible, sin GC, y garantías en tiempo de compilación que encajan con el perfil operativo. El runtime async de Tokio hace realista coordinar el polling de Modbus, las escrituras a SQLite, el sync HTTP, y el subsistema de IA en un solo proceso.

Por qué ONNX como formato de intercambio de modelos: el pipeline de entrenamiento en Python (scikit-learn para los modelos de anomalías, el stack de transformers para NLP) exporta a ONNX, y el runtime en Rust consume exactamente el mismo archivo. Los tests de paridad verifican que las salidas de Rust coincidan bit a bit con las de Python antes de que un modelo se promueva siquiera.

Tradeoff: alcance y peso de mantenimiento. El edge gateway es prácticamente su propio producto dentro de la plataforma — trae su propia versión (2.1.0), su propio modelo de configuración (edge.toml), su propio dashboard, su propio tooling de CLI para la puesta en marcha (validar config, hacer un dry-run de una lectura de registro, convertir un CSV de tags en un borrador de edge.toml). Esa amplitud es la respuesta correcta para un nodo industrial, pero es una cantidad de código nada trivial para mantener sana junto con el resto de la plataforma.

Loading diagram...
Ciclo de vida del modelo: entrenado en Python, exportado a ONNX, y un test de paridad (Rust == Python, bit-identical) es el gate antes de versionar y desplegar por OTA firmado.

2. Arquitectura de IA de tres capas#

En lugar de tratar el ML como una feature pegada a una pantalla, la plataforma tiene tres capas de IA explícitas, cada una con su propio propósito, presupuesto de latencia y ciclo de vida:

  • Capa de inferencia en el edge — un Z-score y un Isolation Forest exportado a ONNX corriendo localmente, diseñada para baja latencia en el edge (objetivo interno: menos de 50ms, sin benchmark publicado).
  • Capa de detección de anomalías — 32 features de ingeniería (temporales, de cambio, z-score, co-variación, calidad de dato, dominio-biogás) alimentadas a una votación por ensemble con umbrales dinámicos por sensor. Las atribuciones SHAP explican por qué se marcó una lectura.
  • Capa de IA predictiva — LSTM + Prophet para el forecasting de biogás/energía, Random Forest + XGBoost para la predicción de fallos de equipo con 4-24 horas de anticipación, más recomendaciones de optimización de parámetros de operación. Aprendizaje continuo con reentrenamiento automatizado; la detección de drift basada en PSI monitorea la degradación de los modelos. Esta capa está marcada como demo en el código: el forecasting y la predicción de fallos no están productivizados todavía.

Cada capa es independiente: el edge sigue funcionando si la nube está caída; la detección de anomalías funciona sin la capa predictiva; la capa predictiva se puede reentrenar sin tocar el runtime del edge. La separación es lo que hace el sistema operable, no solo impresionante.

Tradeoff: peso del ciclo de vida de los modelos. Tres capas significa tres pipelines de entrenamiento, tres registros de modelos, tres caminos de despliegue, tres conjuntos de monitoreo de drift. Es mucha infraestructura para que un solo dev la mantenga — solo vale la pena porque cada capa se paga sola en lo operativo.

Loading diagram...
Tres capas de IA independientes: el edge sigue detectando anomalías aunque el cloud esté caído; la capa predictiva se reentrena sin tocar el runtime del edge. La capa predictiva está marcada como demo en el código.

3. Desarrollo spec-driven con OpenSpec desde el día uno#

El primer commit fue literalmente "init: project structure with openspec specs and tooling". Cada contrato entre apps — backend a frontend, edge a backend, servicio de ML a backend — tiene una spec antes de que se escriba una línea de código. OpenSpec es la fuente de verdad; la implementación tiene que coincidir con ella.

Tradeoff: overhead de proceso al principio. Cada endpoint nuevo tarda más porque la spec va primero. El pago es que cuando un contrato cambia, todos los consumidores ven el diff explícito, y los asistentes de IA que generan el código cliente pueden usar la spec en vez de adivinar a partir de la implementación.

Qué puede hacer Biogas Platform hoy#

  • 5 aplicaciones en un monorepo — backend en Go, edge gateway en Rust, servicio de ML en Python, frontend web en React/Vite, app mobile.
  • Ingesta en tiempo real por MQTT (broker Mosquitto), persistencia en PostgreSQL con Redis para el dato caliente, schemas conscientes de series temporales.
  • Edge gateway autónomo en Rust (v2.1.0) — Modbus TCP/RTU a los PLCs, SQLite offline-first con cola de sync, inferencia de anomalías de baja latencia sobre ONNX (diseñada para <50ms), LLM on-device con agentes de IA, actualizaciones de modelos por OTA con verificación de firma ed25519, PWA de dashboard embebida.
  • IA de tres capas: detección de anomalías en el edge (Z-score + Isolation Forest en ONNX) y en la nube (ensemble Isolation Forest + LSTM Autoencoder) con explicabilidad SHAP —ambas en producción—, más una capa predictiva (forecasts LSTM + Prophet, predicciones de fallo Random Forest + XGBoost con 4-24h de anticipación) marcada como demo en el código, no productivizada.
  • Mantenimiento predictivo por condición real de equipo es el objetivo de roadmap para reemplazar el mantenimiento reactivo o por calendario — hoy la capa predictiva que lo alimentaría está marcada como demo en el código, no productivizada.
  • UI consciente de roles para operarios, personal técnico, supervisores y dueños — vistas y permisos distintos, no toggles sobre un único dashboard.
  • Contratos OpenSpec para cada API entre apps; el plugin de Biome propio (eslint-plugin-biogas-ssot) hace cumplir las convenciones de fuente-única-de-verdad en tiempo de lint.
  • CI/CD en GitLab con almacenamiento de modelos versionado en object storage compatible con S3, rollouts de modelos controlados, y monitoreo de drift que alimenta las decisiones de reentrenamiento.

Qué reconsideraría#

Esperé demasiado para shippear algo. El instinto fue entregar un producto maduro — las tres capas de IA, la app mobile, el modelo de roles, la inferencia en el edge, todo bien hecho antes de mostrarlo. No es así como debería haber ido.

Una entrega más chica y más temprana habría sido la decisión correcta. Un backend que ingiere el dato de los sensores y un dashboard que lo muestra, shippeados en la semana tres, le habrían dado a mi sobrino algo real para usar de inmediato. El feedback de la operación real de una planta habría moldeado las prioridades de lo que viene después. En cambio construí hacia afuera — sumando capas, apps y capacidades — antes de que nada de eso corriera contra el uso diario real.

El costo es invisible desde afuera: la plataforma parece completa y la arquitectura es limpia. El costo está en lo que nunca aprendí porque nada estuvo frente a usuarios lo suficientemente temprano. El próximo producto que construya, voy a shippear la cosa más chica que resuelva el problema original en el primer mes, y ganarme el derecho a sumar capas desde ahí.

Foto de la arquitectura#

Monorepo con cinco aplicaciones y paquetes de soporte:

Loading diagram...
5 apps en un monorepo, con OpenSpec como contrato único entre ellas (validado en lint con un plugin Biome propio).
  • apps/backend — Go + GORM + Gin, API REST, suscriptor MQTT, OpenSpec como fuente de verdad.
  • apps/edge-gateway — Rust (runtime async Tokio), cliente Modbus TCP/RTU a los PLCs, store local SQLite con cola de sync, inferencia con onnxruntime 2.0, LLM local vía llama_cpp, framework de agentes de IA, actualizaciones de modelos por OTA con firma ed25519, PWA de dashboard embebida, métricas Prometheus, endpoints de health.
  • apps/ml-service — Python + scikit-learn, pipelines de entrenamiento, explicabilidad SHAP, exportación a ONNX con tests de paridad.
  • apps/frontend-vite — React 19 + Vite + Mantine + Recharts, dashboards de operario y de analista.
  • apps/mobile — app complementaria en Ionic + Capacitor + Vite para los flujos de campo del operario.
  • packages/eslint-plugin-biogas-ssot — reglas de lint propias que hacen cumplir la fuente-única-de-verdad entre apps.
  • services/ai-assistant — interfaz de consulta en lenguaje natural sobre el dato operativo.

La persistencia es PostgreSQL para el estado canónico, Redis para el dato caliente y el caché, object storage compatible con S3 para los artefactos de modelo y los blobs grandes. La mensajería es Mosquitto MQTT. El despliegue es CI/CD en GitLab con imágenes Docker por app y ruteo en el edge basado en Caddyfile.

Tecnologías

GoMosquitto MQTTRustONNX RuntimePostgreSQLscikit-learnPythonGORMRedisReactTypeScriptMantineViteDockerGitLab CIOpenSpec

Información

Fuente:Curado
Estado:Destacado

¿Te interesa trabajar conmigo?

Hablemos sobre tu próximo proyecto o conocé más sobre mi experiencia.

ContactarDescargar CV