E-commerce · Retail de tecnología
CompumilleniumTienda de tecnología con catálogo sincronizado, pagos con PayPhone y panel propio
E-commerce de laptops y tecnología en Guayaquil: catálogo sincronizado con el proveedor, pagos con PayPhone y un panel de administración propio.
Tecnologías
- Next.js 16
- React 19
- TypeScript
- NestJS 11
- PostgreSQL (pg)
- Cloudflare R2
- Tailwind CSS v4
- shadcn/ui
- next-intl
- Recharts
- TipTap
- React Email + Resend
- ExcelJS
- sharp
- PayPhone
- Turborepo + Bun
- Docker + Railway
- Playwright
- Google Analytics 4
+1.000
fichas de producto en el sitemap
22
secciones del panel
9
correos transaccionales
24
provincias para tarifas de envío
Mi rol
Desarrollo full stack de la tienda, el panel de administración y la API de autenticación, sincronización y respaldos. Entregado a través de NM Tech Studio.
El problema
La tienda venía de un sistema anterior (Stock Manager Advance) y después vivió dentro del ERP del taller. Además, buena parte del catálogo no se escribe a mano: la publica el proveedor Siglo 21 en su API, con precio de costo, fichas técnicas en HTML e imágenes. Hacía falta una tienda propia que se alimente sola de ese catálogo, que cobre con tarjeta en Ecuador sin dejar de aceptar transferencia y efectivo, y que el equipo pueda operar - pedidos, envíos, contenidos, precios - sin pedir un despliegue.
Qué construí
- Tienda con catálogo filtrable por categoría, marca y rango de precio, ficha de producto con galería, carrito y checkout para invitado o usuario registrado.
- Sincronización automática con el catálogo del proveedor Siglo 21: crea y actualiza productos, marcas y categorías, calcula el precio de venta desde el costo con un margen configurable y guarda hasta tres imágenes por producto, convertidas a WebP.
- Tres medios de pago: PayPhone (Cajita de Pagos), transferencia bancaria y efectivo, con comprobantes adjuntos al pedido para los cobros que confirma una persona.
- Checkout que autocompleta los datos a partir de la cédula y registra los checkouts sin terminar, para poder contactar a quien llenó sus datos y no pagó.
- Panel de administración con 22 secciones en cinco grupos - general, catálogo, ventas, marketing y sistema - y roles personalizados con permisos por recurso.
- Nueve correos transaccionales con React Email y Resend - confirmación, actualización, envío, listo para retiro, entrega, cancelación, pago recibido, recordatorio de pago y aviso interno de pedido nuevo -, con textos editables y vista previa desde el panel.
- Portada de 16 secciones reordenables y apagables, páginas de contacto y servicio técnico, catálogos PDF descargables y páginas legales, todo editable desde el CMS.
- Envíos con tarifas por provincia o ciudad sobre las 24 provincias del Ecuador, costo de envío por producto y retiro en tienda.
Cómo está estructurado
Un monorepo con Turborepo y Bun: la tienda y el panel en Next.js, una API en NestJS para autenticación y tareas programadas, y dos paquetes compartidos. Las dos apps apuntan a la misma base PostgreSQL y guardan los archivos en Cloudflare R2.
- apps/web: la tienda pública con rutas en español (/productos, /producto/[slug], /carrito, /finalizar-compra, /cuenta, /catalogos, /servicio-tecnico, /contacto), las páginas de acceso y el panel en /admin.
- apps/api (NestJS): inicio de sesión, registro, refresco de sesión y cambio de contraseña, gestión de usuarios del panel, sincronización con el proveedor, purga de productos y respaldos.
- packages/db: 71 migraciones SQL idempotentes que definen el esquema. packages/auth-contract: la forma del JWT que comparten la web y la API.
- Datos: todo pasa por cuatro fábricas de cliente sobre pg. Las mutaciones son server actions y las rutas API quedan para exportaciones, búsqueda, cupones y pagos.
- Pagos: /api/payments/payphone/prepare registra la transacción pendiente y /api/payments/payphone/confirm la cierra cuando PayPhone devuelve al cliente.
- Tareas programadas en la API: sincronización con el proveedor cada cinco minutos, revisión horaria de respaldos y una purga diaria a las 03:00 de los productos eliminados hace más de 14 días (configurable).
- SEO: sitemap con las fichas de producto y las páginas del CMS, robots que excluye cuenta, checkout, API y URLs con filtros, y JSON-LD de ComputerStore y FAQPage armado con los datos del negocio que se editan en el panel.
- Despliegue: la web y la API como contenedores Docker en Railway, con las migraciones aplicadas antes de levantar la API.
Un catálogo que se mantiene solo
Buena parte del catálogo sale del API del proveedor Siglo 21. La tienda no lo importa una vez: lo sigue, y respeta lo que el equipo cambió a mano.
- Pide páginas de 50 productos - el tope del API - y acumula hasta el tamaño de lote configurado, 200 por defecto, avanzando con un cursor.
- Precio de venta = costo / (1 - margen), con 12% de margen por defecto y un techo de 95% para que el precio nunca llegue a cero ni sea negativo.
- Hasta tres imágenes por producto, convertidas a WebP con sharp y subidas a R2.
- Candados por campo: si alguien fijó a mano el nombre, el precio o la descripción, la sincronización los deja como están y sigue actualizando el resto. Un producto también puede excluirse por completo.
- Al cerrar una vuelta retira lo que el proveedor ya no lista, salvo que la tienda tenga stock propio de ese producto.
- Corre sola dentro de la ventana configurada - por defecto, de lunes a viernes de 08:00 a 18:00 en Guayaquil - y desde el panel se puede lanzar el siguiente ciclo a mano.
Por dentro del sitio

Catálogo con filtros por categoría y marca. 
Ficha de producto con galería, especificaciones, carrito y consulta por WhatsApp.
El panel de administración
Cada módulo resuelve una parte de la operación diaria del negocio, sin salir del panel.
Panel
Tendencia de ventas, estado de los pedidos, productos más vendidos y accesos rápidos en la pantalla de entrada.
Inventario
Alta y edición de productos, importación y exportación en Excel, acciones en lote, detección de duplicados y papelera con restauración.
Categorías y marcas
Taxonomía del catálogo, con imagen y punto focal por categoría, que alimenta los filtros y el menú de la tienda.
Reseñas
Moderación de las reseñas de producto.
Pedidos
Estado, artículos y envío de cada pedido, comprobantes de pago, recordatorios, impresión y un contador de pendientes en la barra lateral.
Checkouts
Quién llenó sus datos en el checkout y no terminó de pagar, con su carrito tal como lo dejó, para poder contactarlo.
Clientes
Listado de clientes con ficha individual.
Cupones
Códigos de descuento que se validan en el checkout.
Envíos
Tarifas por provincia o ciudad sobre las 24 provincias del Ecuador.
Pagos
PayPhone, transferencia con varias cuentas bancarias y efectivo, con la comisión de PayPhone configurable y modo de pruebas.
Suscripciones y correos
Suscriptores del boletín y las nueve plantillas transaccionales, editables y con vista previa.
Contenido y catálogos
Portada, contacto, servicio técnico y páginas legales editables, más los catálogos PDF descargables.
Apariencia y ajustes
Encabezado, pie y tema; identidad, impuestos, idiomas, moneda y el interruptor para abrir o cerrar la tienda.
Integración S21
Credenciales, margen, tamaño de lote y ventana horaria de la sincronización con el proveedor, más una corrida manual.
Respaldos
Copias de la base programadas y bajo demanda, guardadas en R2 con 30 días de retención y descarga por enlace temporal.
Usuarios y roles
Cuentas del equipo y roles personalizados con una matriz de permisos por recurso, que el servidor vuelve a comprobar en cada acción.
Decisiones técnicas
- Un query builder propio con la misma forma encadenada que usa todo el código (.from().select().eq()…), compilado a SQL parametrizado sobre pg. Así la plataforma pasó a una base PostgreSQL propia sin tocar la lógica de negocio, y unas pruebas de paridad vigilan que esa superficie no cambie.
- La autenticación vive en una API NestJS que firma los JWT; la web los verifica localmente con el secreto compartido, así el proxy de Next.js protege rutas y roles sin consultar la API en cada petición.
- Si una pasada de la sincronización fuera a retirar más del 30% del catálogo del proveedor, no retira nada y lo deja registrado: una página corta del API respondida con estado 200 no puede vaciar la tienda.
- Cada intento de pago con PayPhone lleva su propio identificador de transacción - PayPhone rechaza los repetidos - y queda registrado como pendiente antes de abrir la cajita. La confirmación se hace en el servidor, verificando el monto, dentro de los cinco minutos que da PayPhone antes de revertir el cobro.
- La comisión de PayPhone se traslada dividiendo el total entre (1 - tasa) y no sumando un porcentaje, para que la tienda reciba exactamente el valor del pedido. El cálculo vive en un módulo puro que importan el checkout y el servidor, así el total que se muestra y el que se cobra coinciden.
- La analítica de visitas pasó a GA4 y se retiraron las tablas de seguimiento propias, para no gastar base de datos ni memoria del servidor en métricas que Google ya resuelve.
Retos
- Recuperar la galería de la tienda anterior: la migración original desde Stock Manager Advance trajo una sola imagen por producto y dejó fuera las fotos secundarias, que se rescataron sin alterar ninguna imagen principal.
- Publicar datos de un tercero con seguridad: las fichas técnicas del proveedor llegan como HTML y se sanean antes de mostrarse, se descarta el bloque de sindicación de relleno que manda para productos sin ficha real, y un producto sin foto queda en borrador hasta que llega su imagen.
- Convivir con cobros que confirma una máquina y cobros que confirma una persona: PayPhone deja el pedido pagado solo, mientras que la transferencia y el efectivo necesitan comprobantes, con historial para anticipos y saldos.
- Separar la tienda del ERP del taller en un proyecto propio, con su propia base de datos, sin arrastrar las funciones que leían tablas del taller.
Resultado
La tienda está en producción en compumillenium.com.ec, en español, con más de 1.000 fichas de producto en el sitemap, el catálogo del proveedor actualizándose solo y cobros con PayPhone. El equipo gestiona pedidos, envíos, contenidos, precios y respaldos desde el panel, sin tocar código.
