Converse México
may 2026 – hoyDesarrollador Magento
Entré para el backend de Magento y terminé tocando casi todo: módulos nativos, la PWA en React, integraciones, pruebas de rendimiento y análisis de la base de datos. Llevo 19 módulos propios y cambios en más de 30 de los existentes.
La migración de más de 350 mil clientes con todo su historial
Para pasar de la tienda anterior a la nueva hay que llevar a cada cliente con sus direcciones, sus pedidos (con facturas, envíos y notas de crédito), su wishlist y su carrito activo. Sin perder nada, y en una sola noche de mantenimiento.
Lista para producción. En la corrida de prueba: 5.4 millones de filas, entre ellas 184 mil pedidos, 151 mil facturas, 145 mil envíos, 258 mil wishlists y 14 mil carritos activos, sin perder un registro.
Cómo lo resolví
- Scripts en Python que leen los respaldos de mysqldump directamente y en streaming, tabla por tabla. La primera versión cargaba todo en memoria y moría a la mitad por falta de RAM.
- Remapeo de los atributos personalizados de clientes y direcciones (el teléfono y diez campos de dirección de México) a los IDs de la nueva plataforma, y descarte automático de las columnas que la nueva no tiene.
- Un paso final que vuelve a conectar pedidos, wishlist y carritos con el catálogo nuevo por SKU.
- En una de las corridas, el SQL de 2.25 GB llegó corrupto al servidor y el import tronó a la mitad. Desde entonces todo viaja comprimido y se verifica con sha256 antes y después.
- Encontré y corregí un bug de mi propio parser: solo leía el primer bloque INSERT de cada tabla y contaba 2,867 clientes en lugar de cientos de miles.
- Dejé el procedimiento documentado paso a paso para la noche de la migración: mantenimiento, respaldo fresco, limpieza, importación y remapeo.
Con: Python, mysqldump, SQL, gzip, sha256
La ficha de producto no se podía cachear y la tienda empezó a dar 502
Un plugin metía el ID de sesión en el contexto HTTP, así que Fastly guardaba una versión de la página por cada visitante. Además, la plantilla de reseñas imprimía datos del cliente dentro de HTML compartido. Con tráfico alto, PHP no alcanzaba.
Prueba de carga con k6 (10 usuarios, 10 minutos): hit ratio de caché de 98.4 % en 43 mil peticiones, 0 errores 5xx y la página de categoría bajó de 636 ms a 93 ms.
Cómo lo resolví
- Saqué el ID de sesión del contexto HTTP y lo generé en el navegador.
- Los datos del cliente ahora los pinta el JS desde customer-data, no la plantilla cacheada.
- Agregué cache tags por producto a las consultas GraphQL propias, para que Fastly purgue solo lo que cambia.
- Versioné el JS del buscador, que se quedaba un año en caché sin forma de invalidarlo.
Con: plugins de Magento, GraphQL @cache, Fastly, k6
Las preventas se operaban con SQL a mano
Abrir registros, mover productos a una categoría restringida y dar o quitar permisos a cada grupo de clientes se hacía con UPDATE directos a la base.
Unas 3 mil líneas que reemplazaron al módulo anterior y al SQL manual.
Cómo lo resolví
- Un módulo nuevo con una máquina de cinco estados (programada, registro abierto, registro cerrado, venta activa, cerrada) que mueve un cron cada 5 minutos, con botones de respaldo en el admin.
- Guarda el grupo original de cada cliente para regresarlo al cerrar la campaña.
- Se integra con los permisos de catálogo de Adobe Commerce y reindexa en el momento, sin esperar al cron.
- Widget en la tienda para registrarse y exportación a PDF de los registrados.
Con: db_schema, cron, observers, UI Components, CatalogPermissions
Limpiar cuentas basura sin tocar a clientes reales
La base tenía bots, cuentas de prueba, cuentas sin confirmar y abandonadas, mezcladas con clientes reales.
En producción.
Cómo lo resolví
- Siete filtros SQL enchufables por inyección de dependencias, con vista previa en el admin.
- Una cola en la base que procesa un cron por lotes. Justo antes de borrar, vuelve a revisar si el cliente compró o inició sesión mientras esperaba.
- Borra con el repositorio oficial de Magento para que corran los eventos nativos.
- De paso, las cuentas que entran con Google o Facebook ya se marcan como confirmadas.
Con: DI, cola en db_schema, cron, comando de consola
Marcar pedidos como entregados, uno por uno
Llegaban archivos con miles de pedidos para marcar como entregados y se hacía a mano.
En producción.
Cómo lo resolví
- Subes un CSV en el admin y solo se tocan pedidos en proceso y 100 % facturados.
- Si el pedido no tiene envío, lo crea. Con varias fuentes de inventario fallaba al descontar stock, y lo resolví asignando la fuente correcta.
- Lo que no cumple se reporta en un CSV de rechazos, y cada pedido lleva un comentario de auditoría.
Con: Sales, Shipments, MSI
Login con Google que fallaba y menús de cuenta equivocados
El regreso de Google fallaba la validación anti-CSRF porque el state solo vivía en la sesión, y el menú de cuenta mostraba un estado equivocado porque venía de una caché compartida.
Cómo lo resolví
- Guardé el state también en una cookie sensible y lo comparo con hash_equals.
- El menú de cuenta se pinta del lado del cliente.
- El cierre de sesión pasó a POST con form_key.
Con: OAuth, customer-data, RequireJS
Meses sin intereses con tarjeta en la PWA
El formulario de tarjeta de la PWA nunca ofrecía meses; solo el botón de PayPal, en su propio popup.
Unas 400 líneas de pruebas. Probado en sandbox con una Visa nueva a 3 meses y una AMEX guardada a 6.
Cómo lo resolví
- En el backend, una query GraphQL que obtiene el client token de PayPal y un arreglo para que las tarjetas guardadas no perdieran el plazo.
- En el front, Card Fields con los plazos que da el banco, respetando los mínimos del admin, para tarjeta nueva y guardada.
Con: React, PayPal JS SDK, GraphQL, Jest
El carrito dejaba agregar piezas que no había
El botón + dejaba pasar piezas que Magento rechazaba después con «Not enough items for sale».
Cómo lo resolví
- Expuse en GraphQL lo vendible de la talla elegida.
- Un selector de cantidad propio que se detiene en el tope en el mismo clic.
- Separé los errores de stock de los de mínimos y múltiplos, para no bloquear de más.
Con: React, Apollo, GraphQL, Jest
Un chatbot de soporte sin pagar por IA
Querían un chatbot de soporte sin pagar llamadas a un modelo de IA, y con forma de pasar a una persona.
Funciona de punta a punta sin costo por llamadas a IA; la IA se sumará solo en casos específicos.
Cómo lo resolví
- Bot en Botpress con menú: tiendas, pedido, envío, productos y hablar con alguien.
- Firma OAuth 1.0a escrita a mano para consultar la API REST de Magento.
- Paso a un agente humano en LiveChat con su API de chat y webhooks, que Botpress no trae.
- En la PWA, la burbuja se puede arrastrar solo en pantallas táctiles.
Con: Botpress ADK, TypeScript, OAuth 1.0a, LiveChat, Pointer Events
Medir la PWA en un celular lento
Había una auditoría de rendimiento de la PWA y nadie había comprobado qué era cierto.
Confirmé 4 puntos, descarté 2 y encontré 3 riesgos nuevos; uno era un aviso de actualización que veía casi todo visitante nuevo.
Cómo lo resolví
- La medí con k6 browser en un Chromium real, simulando 4G y un CPU cuatro veces más lento.
Con: k6 browser, Chromium
Carga infinita y errores de scripts de terceros
Un loader se quedaba colgado porque un script se cargaba dos veces y la política de seguridad (CSP) bloqueaba scripts inline. Además, el JS de Dotdigital y el de recomendaciones de Adobe tronaban en la ficha.
En producción.
Cómo lo resolví
- Loader compatible con CSP y sin la doble carga.
- Dos módulos pequeños que corrigen los scripts de terceros sin tocar vendor/.
- Pruebas en Cypress para reproducir cada falla antes de corregirla.
Con: CSP, RequireJS, Cypress