ANEXO 39
Arquitectura técnica FARO Connect
Este anexo corresponde a la Fase 11 — Gobierno del sistema, etapa “Arquitectura técnica”. Es el plano donde FARO Connect deja de ser una idea conceptual y se convierte en un sistema construible: módulos, bases de datos, servicios, APIs, motores, seguridad, IA, integraciones, workflow, reportes y escalabilidad.
Hasta el Anexo 38, FARO ya tiene definido:
datos
KPIs
señales
alertas
tensiones
diagnósticos
priorización
recomendaciones
simulaciones
acciones
responsables
workflow
evidencia
seguimiento
reportes
FARO Score
aprendizaje
recalibración
gobierno
seguridad
auditoría
El Anexo 39 responde:
¿Cómo se construye técnicamente FARO Connect para que todo eso funcione de verdad?
1. Objetivo del anexo
El objetivo de este anexo es definir una arquitectura técnica que permita construir FARO Connect de forma:
modular
escalable
segura
auditable
multiempresa
multiindustria
integrable
explicable
mantenible
preparada para IA
preparada para aprendizaje
preparada para versiones Lite, Full, Enterprise y Neural
La idea no es hacer una “mega arquitectura NASA” desde el día uno. Eso sería carísimo, lento y probablemente innecesario.
La idea correcta es:
Diseñar una arquitectura seria desde el inicio, pero implementarla por capas.
Primero una base sólida. Después sofisticación. Nunca al revés.
2. Tesis del Anexo 39
La tesis es:
FARO Connect debe construirse como una plataforma modular de dirección ejecutiva, no como un dashboard ni como un chatbot conectado a datos.
Un dashboard tradicional hace esto:
muestra datos
muestra gráficos
muestra filtros
FARO Connect debe hacer esto:
ingiere datos
normaliza información
calcula KPIs
detecta señales
aplica reglas
genera alertas
identifica tensiones
diagnostica
prioriza
recomienda
simula
crea acciones
asigna responsables
controla workflow
exige evidencia
mide impacto
calcula FARO Score
aprende
recalibra
reporta a Dirección
Eso exige una arquitectura más seria que “React + gráficos + base de datos”. Acá hay motor de dirección, no solo interfaz.
3. Principio técnico central
El núcleo de FARO debe ser determinístico y auditable. La IA debe explicar, redactar, asistir y enriquecer, pero no inventar ni gobernar sola.
Esto es clave.
La IA puede ayudar a:
redactar diagnósticos
explicar alertas
resumir reportes
proponer acciones
comparar escenarios
traducir datos técnicos a lenguaje ejecutivo
Pero el sistema debe tener motores propios para:
calcular KPIs
aplicar reglas
definir umbrales
generar Score
controlar permisos
registrar auditoría
validar evidencia
crear acciones
controlar workflow
Regla de oro:
FARO calcula. FARO gobierna. La IA redacta y asiste.
Si la IA inventa el Score o decide sin trazabilidad, el producto se vuelve indefendible.
4. Arquitectura general FARO Connect
La arquitectura completa puede dividirse en estas capas:
1. Capa de fuentes de datos
2. Capa de ingesta
3. Capa RAW
4. Capa staging
5. Capa de normalización
6. Capa de maestros
7. Capa de modelo ejecutivo
8. Capa de KPIs
9. Capa de señales
10. Capa de reglas
11. Capa de alertas
12. Capa de tensiones
13. Capa de diagnóstico
14. Capa de priorización
15. Capa de recomendaciones
16. Capa de simulación
17. Capa de acciones
18. Capa de responsables / RACI
19. Capa de workflow
20. Capa de evidencia
21. Capa de seguimiento
22. Capa FARO Score
23. Capa de reportes
24. Capa de aprendizaje
25. Capa de recalibración
26. Capa de gobierno y seguridad
27. Capa de IA explicativa
28. Capa frontend / experiencia de usuario
Visualmente:
Fuentes externas
ERP / Excel / CRM / POS / Bancos / WhatsApp / APIs / Documentos
↓
Ingesta
↓
RAW
↓
Staging
↓
Normalización
↓
Modelo ejecutivo
↓
Motores FARO
KPIs → Señales → Reglas → Alertas → Tensiones → Diagnóstico
↓
Decisión
Prioridad → Recomendación → Simulación → Acción → Workflow
↓
Control
Responsable → Evidencia → Seguimiento → Score → Reportes
↓
Mejora continua
Aprendizaje → Recalibración
5. Stack técnico recomendado
Para una primera versión seria, conservadora y escalable:
| Capa | Herramienta recomendada | Motivo |
|---|---|---|
| Frontend | Next.js / React | Web app moderna, modular y escalable. |
| Backend API | Python + FastAPI | APIs rápidas, claras, tipadas y fáciles de documentar. |
| Base de datos principal | PostgreSQL | Robusta, relacional, fuerte para datos estructurados y auditoría. |
| Seguridad por filas | PostgreSQL RLS | Control de acceso por empresa, usuario, sucursal o área. |
| Jobs / tareas | Celery, RQ, BullMQ o similar | Procesos en segundo plano. |
| Cache | Redis | Sesiones, colas, resultados temporales. |
| Archivos | S3 compatible / Supabase Storage / GCS | Evidencias, documentos, reportes. |
| IA | API de modelos LLM con payload estructurado | Explicación, resumen, redacción y asistencia. |
| Observabilidad | OpenTelemetry + Sentry/Grafana/Datadog | Logs, métricas, trazas y errores. |
| Deploy MVP | Render / Railway / Fly.io / Vercel + DB gestionada | Velocidad inicial. |
| Deploy Enterprise | AWS / GCP / Azure | Seguridad, escalabilidad y control. |
Next.js se define oficialmente como un framework React para construir aplicaciones web full-stack; FastAPI es un framework moderno de Python para construir APIs; PostgreSQL soporta Row Level Security mediante políticas por tabla; y OpenTelemetry es un framework abierto para generar, recolectar y exportar telemetría como traces, métricas y logs. ([Next.js][1])
Mi recomendación práctica:
MVP serio:
Next.js + FastAPI + PostgreSQL + Redis + Storage + OpenAI API + auditoría.
Enterprise:
mismo núcleo, pero con mejor aislamiento, RLS fuerte, colas robustas, observabilidad, backups, SSO y entornos separados.
No arrancaría con 20 microservicios. Eso es una fábrica de complejidad antes de tener producto.
6. Monolito modular primero
Para FARO, el mejor inicio técnico no es microservicios. Es un monolito modular bien diseñado.
Estructura:
faro-api/
app/
modules/
auth/
companies/
ingestion/
raw/
staging/
normalization/
master_data/
kpis/
signals/
rules/
alerts/
tensions/
diagnosis/
prioritization/
recommendations/
simulations/
actions/
raci/
workflow/
evidence/
tracking/
score/
reports/
learning/
recalibration/
audit/
ai/
Ventajas:
más rápido de construir
más fácil de entender
menos costo inicial
menos despliegues
menos fricción para MVP
mejor control del modelo
Pero debe nacer modular para que después pueda separarse.
Regla:
Monolito modular no es código desordenado. Es una arquitectura simple con límites claros.
7. Cuándo pasar a microservicios
Solo conviene separar servicios cuando haya:
muchos clientes
alta carga
módulos con escalabilidad distinta
integraciones pesadas
procesamiento masivo
equipos técnicos separados
necesidad de aislamiento fuerte
Servicios que podrían separarse después:
servicio de ingesta
servicio de cálculo de KPIs
servicio de IA
servicio de reportes
servicio de notificaciones
servicio de workflow
servicio de aprendizaje
servicio de simulaciones
Pero no en el día uno.
Dicho claro: microservicios sin volumen real son como comprar camiones antes de tener mercadería.
8. Frontend FARO Connect
El frontend debe ser una aplicación ejecutiva, no un panel genérico.
Módulos visuales:
Home ejecutiva
FARO Score
KPIs
Alertas
Tensiones
Diagnósticos
Recomendaciones
Simulaciones
Acciones
Workflow
Evidencia
Reportes
Responsables
Configuración
Seguridad
Estructura sugerida:
faro-web/
app/
dashboard/
score/
kpis/
alerts/
tensions/
diagnosis/
recommendations/
simulations/
actions/
workflow/
evidence/
reports/
settings/
components/
executive-card/
faro-score-ring/
priority-list/
action-table/
evidence-panel/
report-viewer/
lib/
api-client.ts
permissions.ts
formatters.ts
La interfaz debe tener dos niveles:
1. Vista ejecutiva:
qué pasa, qué importa, qué hacer.
2. Vista técnica:
datos, fórmula, origen, evidencia, SQL, trazabilidad.
El dueño mira la primera. El socio técnico necesita poder abrir la segunda.
9. Backend FARO
El backend debe ser el cerebro operativo.
Responsabilidades:
autenticación
permisos
validación de datos
ingesta
normalización
cálculo de KPIs
reglas
alertas
tensiones
diagnóstico
recomendaciones
acciones
workflow
evidencia
score
reportes
auditoría
IA
Estructura FastAPI conceptual:
from fastapi import FastAPI
app = FastAPI(title="FARO Connect API")
@app.get("/health")
def health_check():
return {"status": "ok"}
@app.post("/companies/{company_id}/kpis/recalculate")
def recalculate_kpis(company_id: str):
# 1. validar permisos
# 2. traer datos normalizados
# 3. recalcular KPIs
# 4. guardar mediciones
# 5. disparar señales
return {
"company_id": company_id,
"status": "kpis_recalculated"
}
Pero cada endpoint debe tener:
validación de permisos
validación de empresa
auditoría
manejo de errores
logs
control de datos sensibles
10. API interna por módulos
Endpoints sugeridos:
/auth/login
/users
/roles
/companies
/branches
/ingestion/upload
/ingestion/sources
/raw/events
/staging/jobs
/normalization/run
/kpis
/kpis/recalculate
/signals
/rules
/alerts
/tensions
/diagnosis
/priorities
/recommendations
/simulations
/actions
/workflows
/evidence
/tracking
/score
/reports
/learning
/recalibration
/audit
/ai/explain
Ejemplo endpoint de acciones:
@app.post("/actions")
def create_action(payload: dict, current_user: dict):
# validar permiso create_action
# validar company_id
# validar action_code contra biblioteca
# asignar responsable
# crear workflow
# registrar auditoría
return {
"status": "created",
"action_id": "ACT_001"
}
11. Base de datos principal
PostgreSQL debe ser el núcleo.
Debe guardar:
empresas
sucursales
usuarios
roles
permisos
fuentes
raw data
staging
maestros
facts
KPIs
señales
reglas
alertas
tensiones
diagnósticos
recomendaciones
simulaciones
acciones
workflow
evidencias
reportes
score
aprendizaje
recalibración
auditoría
No usaría MongoDB como base principal para el corazón del sistema. FARO necesita relaciones, trazabilidad, consistencia, auditoría y SQL. PostgreSQL calza mejor.
Se puede usar JSONB para flexibilidad, pero con estructura.
12. Esquema de base de datos por dominios
Dominios principales:
core
security
data_ingestion
data_model
executive_model
decision_engine
workflow
evidence
score
learning
audit
Ejemplo:
CREATE SCHEMA core;
CREATE SCHEMA security;
CREATE SCHEMA ingestion;
CREATE SCHEMA executive;
CREATE SCHEMA workflow;
CREATE SCHEMA score;
CREATE SCHEMA audit;
Esto ordena sin complicar demasiado.
13. Tablas core
CREATE TABLE companies (
company_id TEXT PRIMARY KEY,
name TEXT NOT NULL,
industry_id TEXT,
status TEXT DEFAULT 'active',
created_at TIMESTAMP DEFAULT now()
);
CREATE TABLE branches (
branch_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
name TEXT NOT NULL,
location TEXT,
active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT now()
);
CREATE TABLE areas (
area_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
area_code TEXT NOT NULL,
area_name TEXT NOT NULL,
active BOOLEAN DEFAULT true
);
14. Modelo de datos RAW
RAW guarda todo como llegó.
CREATE TABLE raw_ingestion_events (
raw_event_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
source_type TEXT NOT NULL,
source_name TEXT,
original_filename TEXT,
payload JSONB NOT NULL,
uploaded_by TEXT,
ingested_at TIMESTAMP DEFAULT now(),
processing_status TEXT DEFAULT 'pending'
);
Ejemplo:
{
"source_type": "excel",
"source_name": "ventas_mensuales",
"payload": {
"columns": ["Fecha", "Cliente", "Producto", "Importe"],
"rows": []
}
}
Regla:
RAW no se toca. RAW se conserva. Si algo falla, se vuelve al origen.
15. Modelo staging
Staging limpia, estructura y prepara.
CREATE TABLE staging_sales (
staging_sale_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
raw_event_id TEXT,
sale_date DATE,
customer_raw TEXT,
product_raw TEXT,
seller_raw TEXT,
branch_raw TEXT,
quantity NUMERIC,
gross_amount NUMERIC,
discount_amount NUMERIC,
net_amount NUMERIC,
currency TEXT,
validation_status TEXT DEFAULT 'pending',
created_at TIMESTAMP DEFAULT now()
);
Staging todavía puede tener errores.
Ejemplos:
cliente no identificado
producto sin maestro
fecha inválida
moneda no reconocida
costo faltante
16. Normalización
Normalización convierte nombres y códigos sueltos en entidades FARO.
def normalize_product(product_raw, product_master):
normalized = product_raw.strip().lower()
for product in product_master:
aliases = [a.lower() for a in product.get("aliases", [])]
if normalized == product["name"].lower() or normalized in aliases:
return product["product_id"]
return None
Ejemplo:
"cemento avellaneda 50kg"
"Cem. Avell. x 50"
"Cemento Avellaneda bolsa"
→ PRODUCT_CEMENT_AVELLANEDA_50KG
17. Tablas maestras
Maestros mínimos:
clientes
productos
proveedores
empleados
sucursales
áreas
vendedores
familias de producto
centros de costo
cuentas financieras
reglas de negocio
Ejemplo producto:
CREATE TABLE dim_products (
product_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
sku TEXT,
product_name TEXT NOT NULL,
product_family TEXT,
supplier_id TEXT,
is_critical BOOLEAN DEFAULT false,
active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT now()
);
Ejemplo cliente:
CREATE TABLE dim_customers (
customer_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
customer_name TEXT NOT NULL,
tax_id TEXT,
customer_segment TEXT,
credit_limit NUMERIC,
active BOOLEAN DEFAULT true,
created_at TIMESTAMP DEFAULT now()
);
18. Modelo ejecutivo
El modelo ejecutivo no guarda datos crudos. Guarda datos listos para dirección.
Tablas tipo fact:
fact_sales
fact_inventory
fact_purchases
fact_accounts_receivable
fact_accounts_payable
fact_cash
fact_hr
fact_actions
fact_workflow
fact_kpi_measurements
Ejemplo:
CREATE TABLE fact_sales (
sale_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
branch_id TEXT,
sale_date DATE NOT NULL,
customer_id TEXT,
product_id TEXT,
seller_id TEXT,
quantity NUMERIC,
gross_amount NUMERIC,
discount_amount NUMERIC,
net_amount NUMERIC,
cost_amount NUMERIC,
gross_margin_amount NUMERIC,
gross_margin_rate NUMERIC,
created_at TIMESTAMP DEFAULT now()
);
19. Motor de KPIs
El motor de KPIs calcula indicadores desde facts.
Ejemplo:
def calculate_gross_margin(net_amount, cost_amount):
if net_amount == 0:
return None
return (net_amount - cost_amount) / net_amount
Ejemplo SQL:
SELECT
company_id,
branch_id,
SUM(net_amount) AS total_sales,
SUM(gross_margin_amount) AS total_margin,
CASE
WHEN SUM(net_amount) = 0 THEN NULL
ELSE SUM(gross_margin_amount) / SUM(net_amount)
END AS gross_margin_rate
FROM fact_sales
WHERE sale_date BETWEEN :start_date AND :end_date
GROUP BY company_id, branch_id;
Tabla de mediciones:
CREATE TABLE kpi_measurements (
measurement_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
branch_id TEXT,
area_id TEXT,
kpi_code TEXT NOT NULL,
period_start DATE,
period_end DATE,
value NUMERIC,
target_value NUMERIC,
confidence NUMERIC,
calculated_at TIMESTAMP DEFAULT now()
);
20. Motor de señales
Las señales detectan movimientos.
Ejemplo:
def detect_margin_drop(current_margin, previous_margin, threshold=0.03):
if current_margin is None or previous_margin is None:
return None
delta = current_margin - previous_margin
if delta <= -threshold:
return {
"signal_code": "MARGIN_DROP",
"severity": "medium",
"delta": delta
}
return None
Tabla:
CREATE TABLE signal_events (
signal_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
signal_code TEXT NOT NULL,
related_kpi_code TEXT,
value_before NUMERIC,
value_after NUMERIC,
delta_value NUMERIC,
severity TEXT,
confidence NUMERIC,
created_at TIMESTAMP DEFAULT now()
);
21. Motor de reglas
Las reglas convierten señales en alertas, tensiones o acciones.
Ejemplo:
def rule_growth_not_profitable(ctx):
conditions = [
ctx["sales_growth"] > 0.10,
ctx["gross_margin_delta"] < -0.03,
ctx["discount_delta"] > 0.02
]
if sum(conditions) >= 3:
return {
"tension_code": "GROWTH_NOT_PROFITABLE",
"severity": "high",
"confidence": 0.82
}
return None
Tabla:
CREATE TABLE business_rules (
rule_id TEXT PRIMARY KEY,
rule_code TEXT NOT NULL,
rule_name TEXT,
rule_type TEXT,
condition_json JSONB,
output_type TEXT,
output_code TEXT,
active BOOLEAN DEFAULT true,
version TEXT DEFAULT '1.0',
created_at TIMESTAMP DEFAULT now()
);
22. Motor de alertas
Alertas = eventos que requieren atención.
CREATE TABLE alert_events (
alert_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
branch_id TEXT,
area_id TEXT,
alert_code TEXT NOT NULL,
severity TEXT,
priority_level TEXT,
title TEXT,
description TEXT,
related_kpis JSONB,
status TEXT DEFAULT 'open',
confidence NUMERIC,
created_at TIMESTAMP DEFAULT now(),
closed_at TIMESTAMP
);
Regla:
alerta no es acción
alerta no es diagnóstico
alerta es señal relevante que requiere lectura o tratamiento
23. Motor de tensiones
Tensión = contradicción sistémica.
Ejemplo:
ventas suben
margen baja
descuento sube
cobranza empeora
→ crecimiento no rentable
Tabla:
CREATE TABLE tension_events (
tension_event_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
branch_id TEXT,
main_area_id TEXT,
tension_code TEXT NOT NULL,
severity TEXT,
priority_level TEXT,
confidence NUMERIC,
related_alerts JSONB,
related_kpis JSONB,
affected_areas JSONB,
status TEXT DEFAULT 'active',
created_at TIMESTAMP DEFAULT now(),
resolved_at TIMESTAMP
);
24. Motor de diagnóstico
Diagnóstico = lectura ejecutiva de lo que pasa.
def generate_diagnosis_from_tension(tension):
if tension["tension_code"] == "GROWTH_NOT_PROFITABLE":
return {
"diagnosis_code": "DIAG_GROWTH_NOT_PROFITABLE",
"title": "Crecimiento no rentable",
"summary": "La empresa crece en ventas, pero pierde calidad de margen y caja.",
"confidence": tension["confidence"]
}
return None
Tabla:
CREATE TABLE diagnosis_events (
diagnosis_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
tension_event_id TEXT,
diagnosis_code TEXT NOT NULL,
title TEXT,
executive_summary TEXT,
probable_causes JSONB,
affected_areas JSONB,
confidence NUMERIC,
status TEXT DEFAULT 'open',
created_at TIMESTAMP DEFAULT now()
);
25. Motor de priorización
Prioriza lo que Dirección debe mirar primero.
def priority_score(impact, urgency, confidence, recurrence, economic_risk):
return round(
impact * 0.30 +
urgency * 0.25 +
confidence * 0.15 +
recurrence * 0.15 +
economic_risk * 0.15,
2
)
Tabla:
CREATE TABLE priority_events (
priority_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
entity_type TEXT NOT NULL,
entity_id TEXT NOT NULL,
priority_score NUMERIC,
priority_level TEXT,
reason TEXT,
created_at TIMESTAMP DEFAULT now()
);
26. Motor de recomendaciones
Recomendaciones desde diagnóstico y prioridad.
def recommend_actions(diagnosis_code, context):
if diagnosis_code == "DIAG_GROWTH_NOT_PROFITABLE":
recommendations = ["auditar_descuentos"]
if context.get("collection_days_high"):
recommendations.append("priorizar_cobranza")
if context.get("commission_misaligned"):
recommendations.append("simular_comision")
return recommendations
return []
Tabla:
CREATE TABLE recommendation_events (
recommendation_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
diagnosis_id TEXT,
recommendation_code TEXT NOT NULL,
title TEXT,
description TEXT,
confidence NUMERIC,
status TEXT DEFAULT 'suggested',
created_at TIMESTAMP DEFAULT now()
);
27. Motor de simulaciones
Las simulaciones evalúan escenarios.
Ejemplo:
def simulate_discount_policy(
current_sales,
current_margin,
expected_sales_drop,
expected_margin_gain
):
simulated_sales = current_sales * (1 - expected_sales_drop)
simulated_margin = current_margin + expected_margin_gain
simulated_margin_amount = simulated_sales * simulated_margin
return {
"simulated_sales": simulated_sales,
"simulated_margin_rate": simulated_margin,
"simulated_margin_amount": simulated_margin_amount
}
Tabla:
CREATE TABLE scenario_runs (
scenario_run_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
scenario_code TEXT NOT NULL,
input_payload JSONB,
output_payload JSONB,
assumptions JSONB,
confidence NUMERIC,
created_by TEXT,
created_at TIMESTAMP DEFAULT now()
);
28. Motor de acciones
Convierte recomendaciones en tareas ejecutables.
def create_action_from_recommendation(recommendation):
action_map = {
"auditar_descuentos": {
"action_code": "ACT_COMMERCIAL_DISCOUNT_AUDIT",
"responsible_role": "ROLE_COMMERCIAL_MANAGER",
"due_hours": 72
},
"priorizar_cobranza": {
"action_code": "ACT_FINANCE_COLLECTION_PRIORITY",
"responsible_role": "ROLE_FINANCE_MANAGER",
"due_hours": 24
}
}
return action_map.get(recommendation)
Tabla:
CREATE TABLE action_events (
action_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
action_code TEXT NOT NULL,
title TEXT,
description TEXT,
responsible_id TEXT,
responsible_role_id TEXT,
priority_level TEXT,
status TEXT DEFAULT 'created',
due_date TIMESTAMP,
required_evidence JSONB,
created_at TIMESTAMP DEFAULT now()
);
29. Motor de workflow
Controla estados y vencimientos.
CREATE TABLE workflow_instances (
workflow_instance_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
entity_type TEXT NOT NULL,
entity_id TEXT NOT NULL,
current_state TEXT NOT NULL,
responsible_id TEXT,
due_date TIMESTAMP,
status TEXT DEFAULT 'active',
created_at TIMESTAMP DEFAULT now()
);
Estados mínimos:
created
assigned
accepted
in_progress
waiting_evidence
waiting_approval
completed
measured
closed
overdue
escalated
blocked
30. Motor de evidencia
Valida que no se cierre sin prueba.
def can_close_action(required_evidence, uploaded_evidence):
required = set(required_evidence)
uploaded = set(uploaded_evidence)
missing = required - uploaded
return {
"can_close": len(missing) == 0,
"missing": list(missing)
}
Tabla:
CREATE TABLE evidence (
evidence_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
entity_type TEXT NOT NULL,
entity_id TEXT NOT NULL,
evidence_type TEXT,
title TEXT,
file_url TEXT,
payload JSONB,
uploaded_by TEXT,
validation_status TEXT DEFAULT 'pending',
sensitive BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT now()
);
31. Motor FARO Score
El Score se calcula combinando componentes.
def faro_score_base(components, weights):
score = 0
for component_code, component_score in components.items():
score += component_score * weights.get(component_code, 0)
return round(score, 2)
Ejemplo:
components = {
"resultado_economico": 70,
"caja_finanzas": 62,
"operacion_stock": 78,
"ejecucion_workflow": 84,
"calidad_datos": 76
}
weights = {
"resultado_economico": 0.20,
"caja_finanzas": 0.22,
"operacion_stock": 0.18,
"ejecucion_workflow": 0.15,
"calidad_datos": 0.05
}
Tabla:
CREATE TABLE faro_scores (
score_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
branch_id TEXT,
area_id TEXT,
score_date DATE NOT NULL,
raw_score NUMERIC,
adjusted_score NUMERIC,
confidence NUMERIC,
positive_drivers JSONB,
negative_drivers JSONB,
explanation TEXT,
created_at TIMESTAMP DEFAULT now()
);
32. Motor de reportes
Genera reportes ejecutivos.
def generate_executive_report(context):
return {
"faro_score": context["faro_score"],
"score_delta": context["score_delta"],
"summary": context["executive_summary"],
"top_priorities": context["top_priorities"][:5],
"critical_actions": context["critical_actions"],
"decisions_required": context["decisions_required"],
"risks": context["risks"]
}
Tabla:
CREATE TABLE reports (
report_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
report_type TEXT NOT NULL,
period_start DATE,
period_end DATE,
title TEXT,
executive_summary TEXT,
faro_score NUMERIC,
confidence NUMERIC,
status TEXT DEFAULT 'draft',
generated_at TIMESTAMP DEFAULT now()
);
33. Capa de IA FARO
La IA debe tener una arquitectura separada del motor determinístico.
motores FARO calculan
↓
payload estructurado
↓
capa IA redacta / explica
↓
respuesta al usuario
Ejemplo payload:
{
"diagnosis": "crecimiento_no_rentable",
"facts": {
"sales_growth": 0.18,
"margin_delta": -0.07,
"discount_delta": 0.06,
"collection_days_delta": 11
},
"confidence": 0.84,
"recommended_actions": [
"auditar_descuentos",
"priorizar_cobranza",
"simular_comision"
]
}
Prompt interno:
Actúa como analista ejecutivo FARO.
Con base únicamente en el payload recibido, redacta una lectura ejecutiva clara.
No inventes datos.
No agregues causas no presentes.
Distingue hechos, hipótesis y recomendaciones.
Incluye:
1. qué pasa,
2. por qué importa,
3. confianza,
4. prioridad,
5. acciones sugeridas.
Regla:
La IA nunca debe recibir más datos de los que el usuario tiene permiso para ver.
34. AI Gateway
Conviene crear un módulo ai_gateway.
Responsabilidades:
filtrar datos por permisos
armar payloads
seleccionar prompt
llamar modelo
validar respuesta
registrar auditoría
guardar costo
guardar trazabilidad
Tabla:
CREATE TABLE ai_interactions (
ai_interaction_id TEXT PRIMARY KEY,
company_id TEXT,
user_id TEXT,
interaction_type TEXT,
prompt_code TEXT,
input_payload JSONB,
output_payload JSONB,
model_name TEXT,
tokens_used INTEGER,
created_at TIMESTAMP DEFAULT now()
);
35. Integraciones
FARO debe integrarse con:
ERP
CRM
POS
Excel
bancos
WhatsApp
APIs externas
documentos
Google Sheets
sistemas internos
Modelo correcto:
cada fuente tiene un adapter
cada adapter convierte fuente externa a formato FARO
RAW conserva original
staging limpia
normalización unifica
Estructura:
integrations/
excel_adapter.py
erp_adapter.py
crm_adapter.py
bank_adapter.py
whatsapp_adapter.py
api_adapter.py
36. Adapter de Excel
def process_excel_upload(file, company_id, uploaded_by):
raw_event = save_raw_file(file, company_id, uploaded_by)
rows = parse_excel(file)
staging_rows = map_rows_to_staging(rows)
return {
"raw_event_id": raw_event["raw_event_id"],
"rows_detected": len(rows),
"rows_to_staging": len(staging_rows)
}
Validaciones:
columnas requeridas
tipos de datos
fechas válidas
monedas válidas
campos obligatorios
duplicados
37. Adapter de bancos
Debe traer:
saldos
movimientos
fechas
conceptos
cuentas
moneda
referencias
Salida FARO:
fact_cash
fact_bank_movements
accounts_receivable_matching
accounts_payable_matching
Regla:
Banco no es contabilidad. FARO debe conciliar, no asumir.
38. Adapter de WhatsApp
WhatsApp puede ingresar información no estructurada.
Ejemplo:
“Cliente Pérez promete pagar el viernes 5 millones”
FARO puede convertirlo en:
{
"event_type": "collection_promise",
"customer": "Cliente Pérez",
"amount": 5000000,
"promise_date": "2026-05-29",
"source": "whatsapp",
"confidence": 0.65
}
Pero requiere validación.
Regla:
WhatsApp puede iniciar un evento. No debe cerrar una decisión sensible solo.
39. Jobs y procesamiento en segundo plano
Procesos que no deberían ejecutarse en la request web:
procesar Excel grande
normalizar datos
recalcular KPIs
generar reportes
enviar notificaciones
correr simulaciones
hacer backtesting
generar embeddings
ejecutar aprendizaje
Estructura:
worker/
ingestion_jobs.py
kpi_jobs.py
report_jobs.py
notification_jobs.py
learning_jobs.py
recalibration_jobs.py
Ejemplo:
def job_recalculate_company(company_id):
normalize_pending_data(company_id)
calculate_kpis(company_id)
detect_signals(company_id)
apply_rules(company_id)
calculate_faro_score(company_id)
40. Event bus interno
FARO puede usar eventos internos.
Ejemplos:
data_ingested
kpi_recalculated
signal_detected
alert_created
tension_created
diagnosis_created
recommendation_created
action_created
evidence_uploaded
action_closed
score_updated
learning_event_created
Tabla:
CREATE TABLE system_events (
event_id TEXT PRIMARY KEY,
company_id TEXT,
event_type TEXT NOT NULL,
entity_type TEXT,
entity_id TEXT,
payload JSONB,
processed BOOLEAN DEFAULT false,
created_at TIMESTAMP DEFAULT now()
);
Esto permite desacoplar módulos sin microservicios.
41. Notificaciones
Canales:
FARO Connect
email
WhatsApp ejecutivo
Slack / Teams
reportes programados
Tabla:
CREATE TABLE notifications (
notification_id TEXT PRIMARY KEY,
company_id TEXT,
user_id TEXT,
channel TEXT,
title TEXT,
message TEXT,
entity_type TEXT,
entity_id TEXT,
status TEXT DEFAULT 'pending',
sent_at TIMESTAMP,
created_at TIMESTAMP DEFAULT now()
);
Regla:
Notificar demasiado mata el sistema. FARO debe notificar por prioridad, no por ansiedad.
42. Seguridad técnica incorporada
La arquitectura debe incluir desde el inicio:
auth
RBAC
ABAC
RLS
company_id obligatorio
audit logs
soft delete
permisos sobre evidencia
permisos sobre reportes
validación de datos sensibles
MFA para roles críticos
No dejar esto para después.
Porque “después agregamos seguridad” suele significar “después reconstruimos medio sistema”.
43. Observabilidad
FARO necesita monitorear:
errores
latencia
jobs fallidos
tiempo de cálculo de KPIs
fallos de integración
uso de IA
costo de IA
reportes generados
acciones vencidas
colas pendientes
Herramientas:
OpenTelemetry
Sentry
Grafana
Prometheus
Datadog
logs estructurados
Ejemplo log:
{
"event": "kpi_recalculation_failed",
"company_id": "COMP_001",
"job_id": "JOB_123",
"error": "missing_cost_amount",
"created_at": "2026-05-28T22:00:00"
}
44. Testing técnico
FARO debe tener pruebas en varios niveles.
unit tests
integration tests
permission tests
data quality tests
workflow tests
score tests
AI payload tests
security tests
regression tests
Ejemplo test de Score:
def test_faro_score_range():
score = faro_score_base(
components={
"resultado_economico": 70,
"caja_finanzas": 60
},
weights={
"resultado_economico": 0.5,
"caja_finanzas": 0.5
}
)
assert 0 <= score <= 100
Ejemplo test de permisos:
def test_user_cannot_access_other_company():
user = {"company_id": "COMP_001", "permissions": ["view_kpis"]}
resource = {"company_id": "COMP_002"}
result = motor_permisos(user, {"permission_code": "view_kpis"}, resource)
assert result["allowed"] is False
45. CI/CD
Pipeline mínimo:
push a repositorio
ejecutar tests
validar lint
validar tipos
migraciones DB controladas
build frontend
build backend
deploy staging
smoke tests
deploy producción con aprobación
Ambientes:
local
development
staging
production
sandbox cliente
Regla:
Nada crítico directo a producción sin pasar por staging.
46. Migraciones de base de datos
Usar herramienta tipo:
Alembic
Prisma migrations
Flyway
Liquibase
Ejemplo Alembic conceptual:
revision: add_action_events_table
down_revision: previous_revision
Regla:
cada cambio de tabla debe versionarse
cada migración debe poder auditarse
no editar base manualmente en producción salvo emergencia registrada
47. Arquitectura MVP
El MVP debería incluir:
auth básica
empresas
usuarios
roles simples
carga Excel
RAW
staging
normalización mínima
maestros básicos
ventas
stock
finanzas básicas
KPIs iniciales
alertas simples
tensiones iniciales
diagnóstico básico
recomendaciones básicas
acciones
responsables
workflow simple
evidencia
FARO Score básico
reporte ejecutivo
IA explicativa controlada
auditoría básica
No incluiría todavía:
ML avanzado
auto-recalibración
multi-tenant enterprise completo
integraciones bancarias complejas
simulaciones sofisticadas
market intelligence
150.000 nodos reales
Eso viene después.
MVP serio no es chico en pensamiento. Es chico en alcance.
48. Arquitectura Full
La versión Full debería sumar:
integraciones API
más módulos
biblioteca amplia de KPIs
biblioteca de tensiones
simulaciones
Action Guides
workflow avanzado
RACI completo
reportes por área
FARO Score ajustado
aprendizaje básico
recalibración sugerida
permisos avanzados
auditoría fuerte
49. Arquitectura Neural
La versión Neural debería sumar:
interdependencias avanzadas
grafos de relaciones
aprendizaje por industria
modelos predictivos
simulaciones multi-escenario
recalibración controlada avanzada
benchmark adaptativo
motor de tensiones profundas
score dinámico por contexto
multiempresa / holding
gobierno avanzado
Posible capa de grafo:
nodos:
KPIs
áreas
acciones
tensiones
clientes
productos
responsables
procesos
relaciones:
impacta
depende_de
bloquea
resuelve
agrava
requiere
Herramientas posibles:
PostgreSQL primero
Neo4j o graph layer después si realmente hace falta
No arrancaría con grafo complejo si todavía no están sólidos los datos base.
50. Arquitectura de carpetas backend
app/
main.py
core/
config.py
database.py
security.py
permissions.py
audit.py
modules/
auth/
routes.py
services.py
schemas.py
ingestion/
routes.py
services.py
adapters/
normalization/
master_data/
kpis/
signals/
rules/
alerts/
tensions/
diagnosis/
recommendations/
simulations/
actions/
workflow/
evidence/
score/
reports/
learning/
recalibration/
ai/
jobs/
tests/
51. Arquitectura de carpetas frontend
src/
app/
dashboard/
score/
kpis/
alerts/
tensions/
actions/
reports/
settings/
components/
ui/
faro/
faro-score-ring.tsx
executive-summary.tsx
priority-card.tsx
action-status-table.tsx
evidence-viewer.tsx
lib/
api.ts
permissions.ts
format.ts
auth.ts
hooks/
types/
52. Contrato API
Ejemplo de respuesta estándar:
{
"success": true,
"data": {},
"meta": {
"request_id": "REQ_001",
"company_id": "COMP_001"
},
"errors": []
}
Ejemplo error:
{
"success": false,
"data": null,
"errors": [
{
"code": "permission_denied",
"message": "No tiene permiso para ver datos financieros."
}
]
}
Esto parece detalle menor, pero ordena todo.
53. Configuración por empresa
FARO debe permitir configuración por cliente.
CREATE TABLE company_settings (
setting_id TEXT PRIMARY KEY,
company_id TEXT NOT NULL,
setting_key TEXT NOT NULL,
setting_value JSONB,
active BOOLEAN DEFAULT true,
updated_at TIMESTAMP DEFAULT now()
);
Ejemplo:
{
"score_weights": {
"caja_finanzas": 0.22,
"resultado_economico": 0.20,
"stock": 0.18
},
"currency": "ARS",
"timezone": "America/Argentina/Mendoza"
}
54. Feature flags
Permiten activar funciones por cliente.
CREATE TABLE feature_flags (
feature_flag_id TEXT PRIMARY KEY,
company_id TEXT,
feature_code TEXT NOT NULL,
enabled BOOLEAN DEFAULT false,
config JSONB,
created_at TIMESTAMP DEFAULT now()
);
Ejemplos:
enable_simulations
enable_neural_engine
enable_whatsapp_ingestion
enable_advanced_score
enable_recalibration
enable_board_reports
55. Manejo de costos de IA
FARO debe controlar costos de IA.
Medir:
tokens por usuario
tokens por empresa
tokens por reporte
tokens por diagnóstico
costo mensual
costo por módulo
Tabla:
CREATE TABLE ai_usage_costs (
usage_id TEXT PRIMARY KEY,
company_id TEXT,
user_id TEXT,
interaction_type TEXT,
tokens_input INTEGER,
tokens_output INTEGER,
estimated_cost NUMERIC,
created_at TIMESTAMP DEFAULT now()
);
Regla:
IA sin control de costos es tarjeta corporativa sin límite.
56. Rendimiento
Puntos críticos:
cálculo de KPIs
carga de reportes
procesamiento de Excel
consultas por empresa
FARO Score
reportes mensuales
IA
Medidas:
índices por company_id
particiones por fecha si crece mucho
jobs asíncronos
cache para reportes
precalcular KPIs
paginación
evitar consultas gigantes en vivo
Índices básicos:
CREATE INDEX idx_fact_sales_company_date
ON fact_sales (company_id, sale_date);
CREATE INDEX idx_action_events_company_status
ON action_events (company_id, status);
CREATE INDEX idx_kpi_measurements_company_kpi_period
ON kpi_measurements (company_id, kpi_code, period_start, period_end);
57. Auditoría dato a decisión
FARO debe poder reconstruir toda la cadena.
dato original
→ raw_event
→ staging row
→ maestro
→ fact
→ KPI
→ señal
→ alerta
→ tensión
→ diagnóstico
→ recomendación
→ acción
→ evidencia
→ cierre
→ Score
→ reporte
Tabla posible:
CREATE TABLE lineage_links (
lineage_id TEXT PRIMARY KEY,
company_id TEXT,
source_entity_type TEXT NOT NULL,
source_entity_id TEXT NOT NULL,
target_entity_type TEXT NOT NULL,
target_entity_id TEXT NOT NULL,
relation_type TEXT,
created_at TIMESTAMP DEFAULT now()
);
Esto es oro para vender a socios técnicos.
58. Diagrama técnico resumido
[Frontend Next.js]
↓
[API FastAPI]
↓
[Permission Engine + Audit]
↓
[PostgreSQL Core]
↓
[Motores FARO]
KPIs | Rules | Alerts | Tensions | Diagnosis | Actions | Workflow | Score
↓
[AI Gateway]
↓
[Reports + Executive UI]
↓
[Learning + Recalibration]
Con procesos paralelos:
[Workers]
ingesta
normalización
cálculos
reportes
notificaciones
aprendizaje
Y almacenamiento:
[PostgreSQL]
datos estructurados
[Object Storage]
evidencia, archivos, PDFs, documentos
[Redis]
colas, cache, jobs temporales
59. Roadmap técnico por etapas
Etapa 1 — Núcleo MVP
usuarios
empresa
carga Excel
RAW
staging
maestros básicos
ventas / stock / finanzas simple
KPIs
alertas
acciones
workflow simple
FARO Score básico
reporte semanal
Etapa 2 — Dirección accionable
tensiones
diagnóstico
recomendaciones
Action Guide
RACI
evidencia
seguimiento
reportes ejecutivos
IA explicativa
Etapa 3 — Sistema serio
simulaciones
score ajustado
auditoría fuerte
permisos avanzados
calidad de datos
aprendizaje
recalibración sugerida
integraciones API
Etapa 4 — Enterprise
multiempresa
multiindustria
SSO
RLS fuerte
observabilidad avanzada
backups enterprise
reportes Directorio
recalibración gobernada
Etapa 5 — Neural
interdependencias profundas
modelos predictivos
grafos
benchmark adaptativo
autoaprendizaje controlado
simulación avanzada
60. Qué debe entender un socio técnico
La explicación corta sería:
FARO Connect es una plataforma modular construida sobre un modelo de datos ejecutivo. Ingiere datos desde múltiples fuentes, los guarda en RAW, los limpia en staging, los normaliza contra maestros, calcula KPIs, detecta señales, aplica reglas, genera alertas, identifica tensiones, diagnostica, prioriza, recomienda, simula, crea acciones, controla workflow, exige evidencia, mide impacto, calcula FARO Score, genera reportes y aprende para recalibrar reglas.
Versión técnica más directa:
No estamos construyendo un dashboard.
Estamos construyendo un motor de dirección empresarial con:
- pipeline de datos,
- modelo ejecutivo,
- motor de reglas,
- motor de workflow,
- motor de score,
- capa de IA explicativa,
- gobierno,
- auditoría,
- aprendizaje.
61. Qué NO debe hacer el equipo técnico
No debe:
empezar por pantallas lindas sin modelo de datos
meter IA antes de ordenar datos
hacer dashboards sin acciones
hacer Score sin fórmula
hacer recomendaciones sin reglas
hacer workflow sin evidencia
hacer multiempresa sin company_id
hacer seguridad al final
hacer microservicios prematuros
hacer todo configurable desde el día uno
Regla:
Primero columna vertebral. Después músculo. Después estética. Si se hace al revés, queda lindo y rengo.
62. Riesgos técnicos principales
| Riesgo | Consecuencia |
|---|---|
| Datos mal modelados | Todo FARO se vuelve débil. |
| No conservar RAW | No se puede auditar ni reprocesar. |
| Maestros pobres | KPIs incorrectos. |
| Score sin trazabilidad | Pierde credibilidad. |
| IA sin control | Inventa o filtra datos sensibles. |
| Workflow débil | Acciones no se ejecutan. |
| Seguridad tardía | Rehacer arquitectura. |
| Sin auditoría | Producto indefendible. |
| Sin modularidad | Escalar se vuelve caro. |
| Sin jobs | Sistema lento e inestable. |
63. Output final del Anexo 39
Al finalizar este anexo, FARO debe tener definido:
1. Arquitectura general.
2. Stack técnico recomendado.
3. Monolito modular inicial.
4. Evolución futura a servicios.
5. Frontend.
6. Backend.
7. API.
8. Base de datos.
9. RAW.
10. Staging.
11. Normalización.
12. Maestros.
13. Modelo ejecutivo.
14. Motor de KPIs.
15. Motor de señales.
16. Motor de reglas.
17. Motor de alertas.
18. Motor de tensiones.
19. Motor de diagnóstico.
20. Motor de priorización.
21. Motor de recomendaciones.
22. Motor de simulaciones.
23. Motor de acciones.
24. Motor de workflow.
25. Motor de evidencia.
26. Motor FARO Score.
27. Motor de reportes.
28. Capa de IA.
29. AI Gateway.
30. Integraciones.
31. Jobs.
32. Event bus interno.
33. Notificaciones.
34. Seguridad técnica.
35. Observabilidad.
36. Testing.
37. CI/CD.
38. Migraciones.
39. MVP.
40. Full.
41. Neural.
42. Feature flags.
43. Costos de IA.
44. Performance.
45. Linaje dato → decisión.
46. Roadmap técnico.
64. Conexión con otros anexos
| Anexo relacionado | Qué recibe desde Anexo 39 |
|---|---|
| Anexo 1-3 | Diagnóstico, procesos y fuentes que alimentan la arquitectura. |
| Anexo 4-10 | Pipeline RAW, staging, normalización y maestros. |
| Anexo 17 | KPIs calculados por el motor técnico. |
| Anexo 19-22 | Señales, reglas, alertas y tensiones. |
| Anexo 23-26 | Diagnóstico, prioridad y recomendaciones. |
| Anexo 27 | Motor de simulaciones. |
| Anexo 28-33 | Acciones, RACI, workflow, evidencia y seguimiento. |
| Anexo 34 | Reportes ejecutivos. |
| Anexo 35 | FARO Score. |
| Anexo 36-37 | Aprendizaje y recalibración. |
| Anexo 38 | Gobierno, permisos, seguridad y auditoría. |
| Anexo 40 | Implementación por fases, backlog y plan de desarrollo. |
La Arquitectura Técnica FARO define cómo se construye FARO Connect por dentro: frontend, backend, base de datos, pipeline de datos, motores de KPIs, reglas, alertas, tensiones, diagnóstico, recomendaciones, acciones, workflow, evidencia, Score, reportes, IA, seguridad, auditoría, aprendizaje y recalibración.