Saltar al contenido
E3 CreaTIC

Documentación técnica

Decisiones arquitectónicas

ADR-001 — Kafka como bus central

Decisión: Todo el pipeline de ingesta pasa por Kafka (no HTTP directo a PostgreSQL).
Motivo: Desacoplamiento productor/consumidor, backpressure natural, replay de eventos, Dead Letter Queue para fallos.
Trade-off: Mayor complejidad operacional; el Routing Consumer requiere semáforos explícitos para evitar condiciones de carrera en commit de offsets.

ADR-002 — Union-Find para correlación de alertas

Decisión: El Correlation Engine usa Union-Find (algoritmo de conjuntos disjuntos) con complejidad O(N · α(N)).
Motivo: Las alertas relacionadas forman grupos naturales. Union-Find es cuasi-lineal, determinístico y fácil de serializar.
Trade-off: Requiere que las estrategias de correlación sean definidas explícitamente; no descubre correlaciones implícitas sin reglas.

ADR-003 — Persistencia políglota

Decisión: 5 motores de almacenamiento distintos para distintos tipos de dato:

  • PostgreSQL: fuente de verdad relacional (incidentes, alertas, configuración)
  • Neo4j: topología como grafo (relaciones entre recursos)
  • OpenSearch: logs y eventos para búsqueda full-text
  • Redis: cache TTL y broker Celery
  • MinIO: objetos binarios (modelos ML, secretos EOE, artefactos de diagnóstico)

Motivo: Cada motor optimizado para su tipo de dato. Un solo PostgreSQL para todo no escala en búsqueda full-text ni en consultas de grafos.
Trade-off: Mayor complejidad operacional. Se mitiga con Docker Compose.

ADR-004 — Multi-tenant by design

Decisión: tenant_id como campo obligatorio en cada modelo ORM y filtro obligatorio en cada query. Extraído del JWT, nunca pasado como parámetro de request.
Motivo: Aislamiento total de datos entre tenants desde el inicio, sin retrofitting posterior.
Trade-off: Cualquier query que olvide el filtro tenant_id es un bug de seguridad. Se mitiga con el TenantContextMiddleware y revisión en PRs.

ADR-005 — Versiones de frontend fijas

Decisión: React 18, Vite 5, TypeScript 5.8, Tailwind 3 — fijos en los tres frontends.
Motivo: react-diff-viewer-continued (usado en el EOE Flow Designer para comparar versiones de flujos) solo soporta React ≤18. Los tres frontends deben estar alineados para evitar superficies de bugs no reproducibles.
Trade-off: No recibir mejoras de React 19 ni Tailwind 4.

ADR-006 — EOE independiente del backend core

Decisión: El Orchestration Engine (EOE) es un microservicio FastAPI separado (eoe-api, puerto 8002 interno) con su propio schema de base de datos y su propia capa de auth.
Motivo: Aislamiento de fallos (un flujo mal configurado no afecta la ingesta), equipos distintos pueden desarrollarlo independientemente, posibilidad de escalado horizontal separado.
Trade-off: Requiere un proxy nginx dedicado y una clave EOE_INTERNAL_API_KEY para la comunicación interna.

ADR-007 — CSS tokens en vez de clases Tailwind con alpha

Decisión: Todos los colores con alpha y valores de tema se definen como variables CSS en frontend/src/index.css. Las clases ECharts/Recharts usan cssVar() / chartTheme() de frontend/src/theme.ts.
Motivo: El selector [class*="bg-violet-5"][class*="\/2"] da falsa coincidencia con border-violet-500/20. Los overrides de light/dark mode requieren selectores CSS controlados.
Trade-off: Requiere disciplina de equipo — no quemar hex en .tsx.

ADR-008 — Celery con QueuePool vs NullPool según el contexto

Decisión: La API FastAPI usa QueuePool de SQLAlchemy; las tareas Celery y los Consumers Kafka usan NullPool.
Motivo: Celery crea procesos fork — compartir conexiones del pool entre procesos padre/hijo provoca SSL SYSCALL error y EOF detected. NullPool crea una conexión nueva por tarea y la cierra al terminar.
Trade-off: Mayor overhead de conexión en tareas Celery de alta frecuencia.