TFG-B2B: Arquitectura para la Trazabilidad Documental y Detección de Cuellos de Botella en Redes B2B mediante Grafos y Generación Sintética
Este repositorio contiene la implementación práctica del Trabajo de Fin de Grado en Ingeniería Informática para la Universidad de Burgos (UBU).
El proyecto propone y desarrolla una arquitectura integral para gestionar la trazabilidad documental en redes Business-to-Business (B2B). Utilizando bases de datos orientadas a grafos y algoritmos analíticos, el sistema permite modelar flujos de trabajo complejos, rastrear el linaje de los datos y detectar cuellos de botella operativos en la cadena de suministro entre empresas.
Ante la escasez de datos B2B públicos (RGPD, secreto comercial), el proyecto integra una fase de generación sintética de redes topológicas realistas mediante el modelo LFR (Lancichinetti-Fortunato-Radicchi), lo que permite validar la arquitectura y las consultas analíticas a gran escala sin depender de datos reales confidenciales.
- Generación sintética de redes B2B con modelo LFR
- Pipeline ETL configurable (generate → load → analyze → seed)
- Trazabilidad documental hacia adelante y hacia atrás (linaje)
- Detección de cuellos de botella con PageRank y Betweenness Centrality
- Análisis de comunidades con Louvain y componentes débilmente conexos (WCC)
- Métricas de riesgo: concentración, discrepancias, plazos, exposición de pago
- Dashboard interactivo con 7 pestañas analíticas
- Portal de empresa autenticado (JWT)
- API REST documentada (Swagger UI)
- Stack completamente contenerizado con Docker Compose
git clone https://github.com/pablomatgom/TFG-B2B.git && cd TFG-B2B
cp .env.example .env
docker compose up -d
# Opcional: poblar la base de datos con datos sintéticos
docker compose --profile pipeline up pipeline-init| Servicio | URL |
|---|---|
| Dashboard | http://localhost |
| API (Swagger) | http://localhost:8000/docs |
| Neo4j Browser | http://localhost:7474 |
| Documentación | http://localhost/docs |
El sistema sigue una arquitectura de tres capas completamente contenerizada con Docker y orquestada tras un proxy inverso Nginx:
┌──────────────────────────────────────────────────┐
│ Frontend Next.js localhost:3000 │
│ Dashboard · Analítica · Pipeline · Empresa │
└────────────────────┬─────────────────────────────┘
│ HTTP / REST
┌────────────────────▼─────────────────────────────┐
│ Backend FastAPI localhost:8000 │
│ Pipeline ETL · Consultas Cypher · Auth JWT │
└────────────────────┬─────────────────────────────┘
│ Neo4j Bolt (7687)
┌────────────────────▼─────────────────────────────┐
│ Neo4j 5 + Graph Data Science │
│ 4 tipos de nodo · 7 tipos de arista │
└──────────────────────────────────────────────────┘
| Nodo | Propiedades clave |
|---|---|
Company |
company_id, node_role (SUPPLIER/BUYER/HYBRID), region, industry_code |
Product |
product_id, sku, criticality, lead_time_baseline_days |
Document |
document_id, doc_type (ORDER/INVOICE/SHIPMENT/CREDIT_NOTE), discrepancy_flag |
TimeBucket |
date, year, month, day |
| Relación | Semántica |
|---|---|
SUPPLIES |
Company → Company (enlace proveedor-comprador) |
SELLS |
Company → Product |
ISSUES |
Company → Document |
SENT_TO |
Document → Company |
CONTAINS |
Document → Product (líneas de pedido) |
FULFILLS |
Document → Document (cadena de trazabilidad) |
Issue_on |
Document → TimeBucket |
Para el esquema completo de propiedades consulta la documentación técnica.
| Capa | Tecnología | Uso |
|---|---|---|
| Frontend | Next.js 16 + React 19 | Dashboard e interfaz de usuario |
| Estilos | Tailwind CSS 4 + MUI 9 | Componentes y diseño |
| Gráficas | Recharts 3 + Tremor | Visualizaciones analíticas |
| Backend | FastAPI 0.136 + Uvicorn | API REST y orquestación del pipeline |
| Base de datos | Neo4j 5 + GDS | Grafo principal y algoritmos analíticos |
| Auth | SQLite + SQLAlchemy + PyJWT + bcrypt | Autenticación JWT y almacén de usuarios |
| Generación sintética | NetworkX + Faker + NumPy/Pandas | Modelo LFR y síntesis de datos |
| Infraestructura | Docker Compose + Nginx | Contenerización y proxy inverso |
| Calidad | ruff + pytest + ESLint + Jest + SonarCloud | Lint, tests y análisis estático |
| CI/CD | GitHub Actions + Hetzner | Integración y despliegue continuos |
# 1. Clonar el repositorio
git clone https://github.com/pablomatgom/TFG-B2B.git
cd TFG-B2B
# 2. Instalar dependencias Python
pip install -r requirements.txt
# 3. Instalar dependencias del frontend
cd frontend && pnpm install && cd ..Copiar el archivo de entorno y ajustar los valores si es necesario:
cp .env.example .envVariables de entorno relevantes:
| Variable | Valor por defecto | Descripción |
|---|---|---|
NEO4J_URI |
bolt://localhost:7687 |
URI de conexión a Neo4j |
NEO4J_USER |
neo4j |
Usuario de Neo4j |
NEO4J_PASSWORD |
AdminUser1234 |
Contraseña de Neo4j |
JWT_SECRET_KEY |
change-me-in-production |
Clave secreta para tokens JWT |
PUBLIC_URL |
(vacío) | URL pública en producción (ej. https://dominio.com) |
En local los valores por defecto funcionan sin modificación. Cambiar
JWT_SECRET_KEYyNEO4J_PASSWORDantes de cualquier despliegue en producción.
# 1. Arrancar Neo4j (el primer arranque descarga el plugin GDS — esperar ~30s)
docker compose up -d neo4j
# 2. Ejecutar el pipeline completo (genera, carga, analiza y siembra usuarios)
python backend/main_cli.py all --rows 300 --clear-db --seed 42
# 3. Arrancar el backend
python -m uvicorn backend.api.main:app --reload --host 0.0.0.0 --port 8000
# 4. Arrancar el frontend (en otra terminal)
cd frontend && pnpm devAbrir http://localhost:3000 e iniciar sesión con cualquier cuenta de empresa generada en el paso 2.
python backend/main_cli.py generate --rows 300 --gamma 2.4 --beta 1.8 --mu 0.30
python backend/main_cli.py load --batch_size_loader 10000 --clear-db
python backend/main_cli.py analyze
python backend/main_cli.py seed# Backend — lint + tests + cobertura
ruff check backend/
python -m pytest tests/ -v --cov=backend
# Frontend — lint + tests + build
cd frontend && pnpm lint && pnpm test:ci && pnpm buildLa CI ejecuta todo lo anterior automáticamente en cada push y publica el análisis en SonarCloud. La CD despliega en Hetzner al hacer merge a main.
backend/
├── api/ Routers FastAPI (health, dashboard, pipeline, analytics, auth, company)
├── auth/ Modelo SQLAlchemy + siembra de usuarios
├── core/ Configuración (dataclass) y utilidades
├── etl/
│ ├── generation/ Sintetizadores LFR (empresas, suministros, productos, documentos)
│ ├── analytics/ Mixins analíticos (macro, trazabilidad, GDS, riesgo)
│ ├── runners/ Orquestadores de cada fase del pipeline
│ └── loader.py Neo4jBulkLoader — carga por lotes
└── main_cli.py Punto de entrada CLI
frontend/
└── src/
├── app/ Páginas Next.js (dashboard, analytics, pipeline, company, login, docs)
├── components/ Componentes React (charts, analytics tabs, dashboard, ui)
├── hooks/ useDbStatus, useFetchTab
├── lib/ api.ts, auth.ts, analytics.ts, brand.ts
└── types/ Interfaces TypeScript
tests/ Unitarios, integración, API y e2e (pytest)
docs/ Documentación técnica (MkDocs)
memoria_ubu/ Memoria del TFG en LaTeX (plantilla oficial UBU)
nginx/ Configuración del proxy inverso
data/ CSVs generados, exports Neo4j, SQLite de usuarios (git-ignorado)
docker-compose.yml
| Actor | Caso de uso | Descripción |
|---|---|---|
| Analista de red | Ejecutar el pipeline | Genera una red sintética, la carga en Neo4j y lanza el análisis topológico completo |
| Analista de red | Visualizar cuellos de botella | Consulta el ranking GDS (PageRank, Betweenness) para identificar empresas críticas |
| Analista de red | Explorar comunidades | Detecta clústeres de empresas mediante Louvain y analiza su cohesión interna |
| Empresa (comprador) | Portal de empresa | Accede a su perfil, lista de documentos recibidos y actualiza su estado |
| Empresa (proveedor) | Trazabilidad de documentos | Rastrea el linaje de una orden: de qué factura proviene, qué albarán la cumplimenta |
| Empresa (proveedor) | Analítica de riesgo | Consulta su tasa de discrepancias, cumplimiento de plazos y exposición de pago |
| Administrador | Registro de usuarios | Crea cuentas de empresa vinculadas a nodos Company de Neo4j |
La API REST corre en http://localhost:8000. Documentación interactiva en /docs (Swagger UI).
| Método | Endpoint | Descripción |
|---|---|---|
GET |
/api/health |
Estado de conexión con Neo4j |
GET |
/api/dashboard/macro |
KPIs globales y serie temporal |
POST |
/api/pipeline/run |
Lanza el pipeline ETL en segundo plano (202) |
GET |
/api/pipeline/status |
Estado actual del pipeline |
GET |
/api/analytics/gds |
PageRank, Betweenness, Louvain, WCC |
GET |
/api/analytics/risk/supplier-score |
Scoring de riesgo por proveedor |
GET |
/api/analytics/risk/buyer-fragility |
Fragilidad de compradores |
GET |
/api/analytics/risk/geographic |
Riesgo geográfico |
GET |
/api/analytics/lineage/backward |
Trazabilidad hacia atrás |
GET |
/api/analytics/lineage/forward |
Trazabilidad hacia adelante |
GET |
/api/analytics/discrepancy-suppliers |
Tasa de discrepancias por proveedor |
GET |
/api/analytics/lead-time |
Cumplimiento de plazos de entrega |
GET |
/api/analytics/payment |
Exposición de pago |
POST |
/auth/login |
Autenticación — devuelve token JWT |
GET |
/api/company/me |
Perfil de la empresa autenticada |
GET |
/api/company/documents |
Documentos de la empresa autenticada |
Todos los endpoints de
/api/company/*y/auth/merequieren cabeceraAuthorization: Bearer <token>.
docker compose up -d neo4j# Levanta Neo4j + Backend + Frontend + Docs + Nginx
docker compose up -d
# Pipeline de inicialización como contenedor de un solo uso
docker compose --profile pipeline up pipeline-init| Servicio | Puerto interno | Descripción |
|---|---|---|
neo4j |
7474 / 7687 | Base de datos de grafos + GDS |
backend |
8000 | API FastAPI |
frontend |
3000 | Dashboard Next.js |
docs |
— | Sitio MkDocs |
nginx |
80 / 443 | Proxy inverso público |
pipeline-init |
— | Init container (perfil pipeline) |
- OBJ-1: Diseñar un modelo de grafo que represente fielmente los flujos documentales (órdenes, facturas, albaranes, notas de crédito) entre empresas en una red B2B.
- OBJ-2: Implementar un generador de datos sintéticos basado en el modelo LFR que reproduzca la topología libre de escala y la estructura de comunidades observada en redes reales.
- OBJ-3: Desarrollar un pipeline ETL completo que cargue los datos generados en Neo4j de forma eficiente mediante procesamiento por lotes.
- OBJ-4: Aplicar algoritmos de grafos (PageRank, Betweenness Centrality, Louvain, WCC) para detectar cuellos de botella y empresas críticas en la red.
- OBJ-5: Cuantificar el riesgo de la cadena de suministro mediante métricas de concentración de proveedores, tasa de discrepancias, cumplimiento de plazos y exposición de pago.
- OBJ-6: Exponer toda la analítica a través de una API REST y un dashboard interactivo accesible por las empresas participantes.
- Exportación de compradores cruzados — el endpoint de síntesis de compradores devuelve actualmente una lista vacía porque
cross_buyers.jsonno se genera en la fase de análisis. Es la deuda técnica de menor coste y mayor impacto inmediato: requiere implementar un único método en el módulo de riesgo cruzado y registrarlo en el orquestador de análisis. - Carga incremental sin destrucción de datos — cada ejecución del pipeline borra el grafo entero antes de cargar la nueva red. Sería útil poder realizar cargas esporádicas que se incorporen al grafo existente sin destruirlo, acumulando instantáneas de la red para analizar su evolución temporal.
- Analítica en tiempo real — el dashboard muestra el estado del grafo en el momento del último análisis. Sustituir el modelo de precálculo por suscripciones mediante WebSockets o Server-Sent Events haría la interfaz mucho más dinámica.
- Soporte multi-grafo — gestionar varias redes B2B independientes bajo un mismo despliegue, con selección de grafo activo por usuario, permitiría comparar estructuras de suministro de distintos sectores dentro de la misma plataforma.
- Visualización interactiva del grafo — los gráficos actuales son estadísticos. Integrar Cytoscape.js o Sigma.js permitiría explorar visualmente la topología, navegar por los clústeres y seleccionar nodos para inspeccionar sus relaciones directamente en el navegador.
- Adaptación a datos reales con privacidad diferencial — todo el sistema opera sobre datos sintéticos para evitar las restricciones del RGPD. La línea más ambiciosa sería desarrollar un módulo de anonimización diferencial que permitiera cargar datos B2B reales preservando la privacidad de las entidades, validando así los algoritmos contra redes de suministro reales.
Pablo Maté Gómez
Grado en Ingeniería Informática — Universidad de Burgos (UBU)
- GitHub: @pablomatgom
- Email: pmatego@gmail.com
Este proyecto está distribuido bajo la licencia MIT. Consulta el archivo LICENSE para más detalles.