Atlas
Pipeline de catálogo distribuido entre proveedor mayorista,
base intermedia y tienda WooCommerce.
Sobre el sistema
Sistema ATLAS es un pipeline automatizado que mantiene sincronizado el catálogo de la tienda WooCommerce de 7htech.com con el feed de un proveedor mayorista. El sistema ingiere ~28.000 productos del origen, los normaliza en una base intermedia y proyecta un subconjunto curado de ~18.700 SKUs a la tienda final con precios calculados, categorías mapeadas, stock real y ofertas activas.
El sistema fue diseñado para resolver tres problemas: volumen (un catálogo de decenas de miles de SKUs no puede mantenerse a mano), volatilidad (precios y stock cambian cada 30 minutos en origen) y consistencia (cada producto pasa por reglas de pricing, mapeo de categorías y enriquecimiento antes de publicarse). La capa intermedia en Baserow actúa como buffer y lugar de enriquecimiento: permite intervenir, auditar y curar datos sin tocar el origen ni el destino.
Capacidades del sistema
Cada capacidad está implementada como un módulo independiente dentro del pipeline. Son ortogonales: añadir o reemplazar una no obliga a tocar las demás.
Arquitectura del pipeline
El sistema sigue un patrón clásico ETL en tres capas con una base intermedia que actúa de buffer. El origen no se acopla nunca al destino: si la tienda cae, el origen sigue ingiriendo; si el origen cambia de formato, solo se rehace la primera capa. Toda la orquestación corre en n8n self-hosted en Docker.
Flujos de sincronización
El pipeline está dividido en tres workflows independientes que pueden ejecutarse y diagnosticarse por separado. F1 y F2 son automáticos y programados; F3 se ejecuta on-demand cuando hay que reconstruir el árbol de categorías.
| FLOW | FUNCIÓN | FRECUENCIA | VOLUMEN | ESTADO |
|---|---|---|---|---|
F1ingest |
Origen → Staging. Lee el feed XML, normaliza, calcula checksum por registro y solo actualiza filas modificadas en la base intermedia. | 60 min Cron |
~28K productos ~200 cambios/ciclo |
● ESTABLE |
F2publish |
Staging → WooCommerce. Para cada producto modificado calcula precio con margen, mapea categorías, prepara imágenes y crea/actualiza vía REST API. Versión 10. | 60 min Cron |
~18.7K productos SplitInBatches |
● ESTABLE |
F3cat-sync |
Sync de árbol de categorías. Dos fases: alta plana (POST) y aplicación de jerarquía padre-hijo (PUT). Triggers manuales independientes. | On-demand Manual |
534 categorías | ● COMPLETADO |
Modelo de precios
El precio final se calcula dinámicamente en cada ciclo a partir del precio de distribuidor y el canon medioambiental, multiplicado por un margen que se define por categoría en la propia tabla maestra de categorías. Esto permite ajustar la estrategia comercial sin tocar el código del workflow: cambiar un margen es editar una celda.
Mapeo y jerarquía de categorías
534 categorías del proveedor se proyectan al árbol de WooCommerce manteniendo relaciones padre-hijo. La sincronización se hace en dos fases controladas porque WooCommerce no acepta crear una categoría hija con referencia a un padre que aún no existe.
| FASE | OPERACIÓN | MÉTODO | SALIDA |
|---|---|---|---|
| Fase 1 Alta plana |
Crear las 534 categorías sin relaciones. Se ignora parent en este paso. Se obtiene el ID de WooCommerce de cada categoría y se persiste en la tabla maestra de la base intermedia. |
POST |
534 IDs nuevos |
| Fase 2 Jerarquía |
Recorrer la tabla maestra y aplicar a cada categoría su parent ahora que todos los IDs existen. Se reconstruye el árbol completo. |
PUT |
Árbol completo |
Cada fase se dispara desde un Manual Trigger independiente dentro del mismo workflow. Esto permite ejecutar solo Fase 2 si se han modificado relaciones sin crear categorías nuevas, o ejecutar todo desde cero en caso de reset.
Stack tecnológico
Toda la infraestructura es self-hosted. Cero dependencia de SaaS de pago para la orquestación o el almacenamiento intermedio. El único coste recurrente es el del propio hosting de la tienda y, próximamente, el uso de la API de Claude para enriquecimiento de descripciones.
Lecciones técnicas
Hallazgos surgidos durante el desarrollo y la operación del sistema. No son curiosidades: son los puntos donde el sistema falló silenciosamente y hubo que entender por qué. Documentarlos aquí evita repetirlos en futuros ecosistemas.
-
DIFF
Checksums se leen, no se recalculanComparar la huella almacenada con una recalculada al vuelo en lectura provocaba mismatches falsos por diferencias de tipo (booleanos como enteros, espacios en blanco, orden de claves). Solución: leer y comparar siempre el checksum almacenado tal cual está en la base. Excluir además los campos volátiles del cálculo (como flags de activación).
-
PERF
Memoria en Code nodes con datasets grandesAdjuntar un objeto auxiliar (mapa de 500+ entradas) a cada uno de los miles de items hace que la memoria explote. El patrón correcto: mantener el objeto en un nodo upstream y referenciarlo downstream con
$('NodeName').first().json.fieldName. La diferencia es de orden de magnitud. -
API
WooCommerce: categorías como objeto, no stringEl endpoint de productos espera
categories: [{ id: 12 }], no[{ name: "Cables" }]ni el ID a pelo. El error es silencioso: la petición se acepta pero la categoría no se asigna. De aquí la importancia de mantener el mapa de IDs sincronizado en la base intermedia. -
PAGE
Paginación por defecto en lecturasLos nodos nativos de Baserow devuelven 50 registros si no se les indica explícitamente lo contrario. Para datasets grandes hay que activar «Return All». Cuando la entrada upstream ya es masiva, además hay que poner el nodo en modo «Execute Once» para evitar una ejecución por cada item.
-
FMT
Arrays con escape doble en el feed XMLEl campo de imágenes en el feed llega como una cadena con comillas dobles escapadas. Antes de hacer
JSON.parse()hay que normalizar las comillas con.replace(/""/g, '"'). Si se intenta parsear directo, el flujo falla en el primer producto con varias imágenes. -
VAR
«items» es palabra reservada en Code nodesEn modo «Run Once for All Items», la variable
itemsya está reservada por el runtime de n8n. Usar nombres alternativos (productos,rows) evita colisiones silenciosas que se manifiestan como datos vacíos sin que ningún nodo marque error. -
LOOP
SplitInBatches requiere feedback al inputEl bucle de batches no avanza si la rama de procesamiento no devuelve datos al nodo de origen. Es un detalle no documentado que provoca que el workflow procese solo el primer batch y se dé por terminado. La rama tiene que cerrar el círculo, aunque sea con un
NoOp. -
PORT
Las credenciales no viajan con el JSONAl exportar un workflow para versionarlo o moverlo de instancia, las credenciales se descartan. Hay que reasignarlas a mano en el destino. Documentar cuáles necesita cada workflow es parte del ciclo de despliegue.
-
FLOW
Múltiples Manual Triggers en un solo workflowUn mismo workflow puede tener varios Manual Triggers como puntos de entrada independientes. Útil para mantener bajo el mismo «techo» operaciones relacionadas (alta de categorías + aplicación de jerarquía) sin obligar a ejecutarlas siempre juntas.
Competencias demostradas
Resumen de las habilidades técnicas aplicadas en este sistema. Cada bloque representa un dominio donde el conocimiento se ha construido iterativamente, sesión a sesión, hasta tenerlo en producción y mantenido.
- n8n self-hosted en Docker
- 3 workflows en producción
- Triggers cron + manual
- SplitInBatches con loops correctos
- Code nodes con gestión de memoria
- Baserow API HTTP y nodo nativo
- Diseño relacional con campos Link
- Filtros condicionales y «Return All»
- Modelado de tabla maestra con metadatos
- REST API v3 (products, categories, media)
- Mapeo de categorías ID-based
- Multi-imagen y galerías
- Stock y ofertas en tiempo real
- Sincronización jerárquica en dos fases
- Ingesta XML del proveedor
- Normalización de campos heterogéneos
- Hash y diff por checksum
- Idempotencia y re-ejecutabilidad
- Curado y enriquecimiento intermedio
- Arquitectura ETL en tres capas
- Desacoplo origen ↔ destino
- Decisiones coste cero / self-hosted
- Documentación técnica viva
- Versionado iterativo (F2 v1 → v10)
- Integración con Claude API
- Generación de descripciones únicas
- Estrategia anti-duplicado SEO
- Caching para reducir coste de inferencia
Próximas fases
skipped=false escriben correctamente el ID Woo en la base.