E-commerce · Retail de tecnología
PCCoreTienda de tecnología con el catálogo del mayorista al día y el seguimiento de reparaciones del taller
Tienda online de PCCore: catálogo sincronizado con el mayorista, pago con PayPhone, transferencia o efectivo, y seguimiento de reparaciones por QR.
Tecnologías
- Next.js 16
- React 19
- TypeScript
- NestJS 11
- PostgreSQL
- Bun + Turborepo
- Tailwind CSS v4
- shadcn/ui
- next-intl
- React Hook Form + Zod
- TipTap
- Recharts
- React Email + Resend
- ExcelJS
- sharp
- Cloudflare R2
- PayPhone
- Bun test · Playwright
- Docker
- Railway

22
secciones en el panel de administración
9
correos transaccionales editables
3
formas de pago
Mi rol
Desarrollo full stack de la tienda - catálogo, checkout, cuentas de cliente y panel de administración -, desde la integración con el mayorista y la migración de la tienda anterior hasta el despliegue en Railway. Entregado a través de NM Tech Studio.
El problema
PCCore vende computadoras, impresoras y accesorios en Durán, y además repara equipos. Su tienda online anterior corría en Stock Manager Advance, sobre MySQL, separada del sistema del taller: eran el mismo negocio y los mismos clientes, pero quien ya había dejado una laptop en reparación era un desconocido al comprar, y saber en qué iba una reparación o cuánto iba a costar obligaba a llamar al local. La tienda nueva tenía que vender en línea con el catálogo de su mayorista, Siglo 21, y a la vez ser la puerta de entrada al servicio técnico.
Qué construí
- Tienda con catálogo filtrable por categoría, marca y rango de precio, búsqueda, ficha de producto con galería, carrito y checkout para invitado o cliente registrado.
- Pagos con PayPhone, transferencia bancaria o efectivo, y entrega a domicilio con tarifa por provincia o ciudad, o retiro en tienda.
- Cuentas de cliente con panel, historial de pedidos, direcciones, perfil y cambio de contraseña.
- Sincronización automática con la API del mayorista Siglo 21: precio con el margen configurado, categoría, marca, ficha técnica e imágenes alojadas en Cloudflare R2.
- Seguimiento público de reparaciones: el QR impreso en la orden del taller, o el número de orden con la cédula, muestra la etapa, el informe del técnico, las notas y el presupuesto.
- Página de servicio técnico editable desde el panel - servicios, proceso, zonas de cobertura y preguntas frecuentes - con un formulario que arma la solicitud y la envía por WhatsApp.
- Panel de administración con 22 secciones en cinco grupos: general, catálogo, ventas, marketing y sistema.
- Nueve correos transaccionales enviados con Resend - confirmación del pedido, pago recibido, listo para retirar, recordatorio de pago y otros -, con plantillas editables y vista previa en el panel.
- Analítica propia: visitas, vistas de producto y búsquedas en ventanas de 7, 30 y 90 días, con los productos más vistos y lo que más se busca.
Cómo está estructurado
La tienda es NovaCart - la misma plataforma de Rolo Electronics - en su propio workspace de Bun con Turborepo, dentro del monorepo del taller. Se despliega aparte y con el taller comparte solo la base PostgreSQL.
- apps/web: Next.js 16 con la tienda y el panel de administración en una sola aplicación; las escrituras son server actions y las rutas de API quedan para exportaciones, pagos y consultas públicas.
- apps/api: NestJS 11 para la autenticación y las tareas programadas - la sincronización con el mayorista, la purga de productos borrados y los respaldos -.
- packages/db con 59 migraciones SQL, fuente única del esquema, y packages/auth-contract con el contrato JWT que comparten la web y la API.
- Datos por SQL parametrizado sobre pg a través de cuatro fábricas de clientes, sesión con JWT HS256 que la web verifica localmente con el secreto compartido, y archivos en Cloudflare R2.
- Refresh tokens rotativos: cada uno se usa una sola vez y se guarda como hash SHA-256; si alguien reutiliza uno viejo, se cierran todas las sesiones del usuario. El ingreso se bloquea tras intentos fallidos.
- Rutas en español (/productos, /servicio-tecnico, /seguimiento) con inglés y francés activables desde el panel; el sitemap y el hreflang anuncian solo los idiomas activos.
- Despliegue en Railway como dos servicios - la API y la web -, cada uno con su Dockerfile, contenedor sin root y healthcheck, que en la API comprueba también PostgreSQL. Los respaldos de la tienda van a R2 con su propia programación.
- Pruebas con Bun test en la web y la API, que corren en CI junto al build en cada push y pull request, más cinco archivos de pruebas end-to-end con Playwright.
El catálogo, sincronizado con el mayorista
La API de la tienda recorre la lista de productos de Siglo 21 por páginas y la convierte en productos de la tienda, con precio, categoría, marca, ficha técnica e imágenes.
- Pasadas automáticas dentro del horario que se fija en el panel - por defecto, de lunes a viernes de 8:00 a 18:00, hora de Ecuador -, con intervalo y tamaño de lote configurables y un botón para correrla a mano en cualquier momento.
- Precio = costo ÷ (1 − margen) y, si la tienda publica con IVA incluido, × (1 + IVA). El margen es un porcentaje del precio de venta, no un recargo sobre el costo: con un costo de $1.123,19 y un margen del 20%, la venta neta es $1.403,99, y con el 15% de IVA se publica en $1.614,59.
- Nombre, precio y descripción se pueden fijar a mano en cada producto, o sacarlo de la sincronización; la pasada respeta lo fijado y deja en el historial del producto lo que el proveedor quiso cambiar, firmado como «Siglo 21».
- La ficha técnica que el proveedor manda en HTML se limpia antes de guardarse y solo conserva tablas, listas y texto.
- Reglas de categorías portadas de un plugin de WordPress, y alias de marcas - «HPINC» termina en «HP» - para que la pasada siguiente no vuelva a crear el duplicado.
- Cada pasada queda registrada con lo creado, lo actualizado y lo desactivado, y su detalle se abre desde el panel.
Seguimiento de reparaciones desde la tienda
El taller y la tienda comparten la base, así que el seguimiento no pasa por la API del ERP: la página lee la orden directamente, solo en lectura, y se la muestra al cliente con la misma credencial que tiene en el papel.
- Dos entradas: el QR impreso en la orden abre /seguimiento con su token y la ficha aparece sin escribir nada; a mano, se consulta con el número de orden y la cédula del titular.
- La ficha muestra la etapa - recibido, en proceso, listo, entregado -, el equipo, la falla, los accesorios, el informe del técnico, las notas del taller y el presupuesto con sus importes.
- Cada consulta es una lectura fresca, sin caché de página: una respuesta guardada mostraría «en reparación» horas después de que el equipo estuviera listo.
- Un token que no existe no termina en un 404 sino en el formulario con un aviso: el papel puede estar borroso y el camino manual sigue abierto.
- En el teléfono la ficha queda justo debajo del título, para que quien escanea el QR vea el estado sin bajar.
- Las URL con token llevan noindex y el sitemap solo publica el formulario vacío; la cabecera de la tienda lleva el acceso «Consulta tu equipo».
SEO local para el servicio técnico
La página de servicio técnico es la que responde a quien busca una reparación en Durán y Guayaquil, así que su marcado y su texto salen de los mismos datos que se editan en el panel.
- Datos estructurados ComputerStore - un subtipo de LocalBusiness - desde un editor de datos del negocio: dirección, teléfono, horario y coordenadas.
- Un grafo con el negocio, el Service con su catálogo de servicios y las zonas atendidas - Durán, Guayaquil y Guayas -, el FAQPage con las mismas preguntas que se ven en pantalla y la ruta de migas.
- Teléfono y horario también en texto rastreable, leídos de la misma configuración que el marcado para que nunca se contradigan; la pregunta del horario desaparece si no hay horario cargado.
- Enlaces a las categorías del catálogo desde el servicio técnico: quien viene por una reparación muchas veces necesita el repuesto, y la página dejó de ser un callejón sin salida para los rastreadores.
- robots.txt excluye panel, cuenta, carrito, checkout y autenticación en los tres idiomas, además de las rutas de API y los parámetros de filtro del listado; el sitemap se regenera cada hora.
- Título absoluto en servicio técnico, para que la plantilla no repita la marca y empuje el título más allá del corte de Google.
Por dentro del sitio

Catálogo con filtros por precio, categoría y marca. 
Ficha de producto con galería, precio, carrito, compra directa y consulta por WhatsApp. 
Página de servicio técnico que lleva clientes al taller. 
Seguimiento de reparaciones: número de orden o QR más la cédula del titular.
El panel de administración
Cada módulo resuelve una parte de la operación diaria del negocio, sin salir del panel.
Resumen
Ventas y su tendencia, pedidos por estado, los productos más vendidos y las visitas de los últimos 30 días, con accesos rápidos al resto del panel.
Analítica
Visitas, vistas de producto y búsquedas propias en ventanas de 7, 30 y 90 días, con los productos más vistos y las búsquedas más frecuentes.
Productos
Alta, edición e importación desde Excel, galería de imágenes, detección de duplicados, historial de cambios y campos fijados a mano para que la sincronización no los pise.
Categorías y marcas
La taxonomía que alimenta los filtros de la tienda; las variantes de marca que manda el proveedor se funden por alias en una sola.
Reseñas
Moderación de las reseñas de producto, una por una o en lote.
Pedidos
Estados según se envíe o se retire, edición de líneas y envío, cobro de saldo, recordatorio de pago, recibos de pago adjuntos e impresión; la barra lateral cuenta los que esperan algo.
Checkouts abandonados
Quien completó sus datos en el checkout y no pagó, con nombre y teléfono para llamarle.
Clientes
Ficha de cada comprador con su documento, sus pedidos, lo gastado y el ticket promedio, y la opción de bloquear la cuenta.
Cupones
Descuentos con sus reglas de uso, validados en el checkout.
Envíos
Tarifas por provincia o ciudad sobre las 24 provincias del Ecuador, costo propio por producto y retiro en tienda sin cargo.
Pagos
PayPhone con su comisión trasladada al total, transferencia con las cuentas bancarias de la tienda y efectivo.
Correos y boletín
Nueve plantillas transaccionales con variables y vista previa, y la lista de suscriptores del boletín.
Contenido
Portada, banners, franjas de productos, testimonios, preguntas frecuentes, páginas y la página de servicio técnico, editables sin desplegar código.
Integración Siglo 21
Margen, horario y lote de la sincronización, historial de cada pasada con su detalle, y cuántos precios cambiaría un margen nuevo antes de guardarlo.
Ajustes
Identidad y colores, impuestos, idiomas activos, datos del negocio para el marcado estructurado, cabecera y pie, y el interruptor que cierra la tienda.
Usuarios, roles y respaldos
Roles administrador, editor y lector, roles a medida sobre 14 recursos, y respaldos de la tienda en R2, todo reservado al administrador.
Decisiones técnicas
- Una base compartida con el taller, con dueños separados: la tienda conserva sus 59 migraciones SQL y el taller las suyas en Prisma. Los cruces son lecturas puntuales - el seguimiento lee las órdenes, el checkout lee el padrón de clientes -, y el respaldo de la tienda enumera sus propias tablas, porque las dos plataformas conviven en el mismo esquema: el taller nombra las suyas en español y la tienda en inglés.
- PostgreSQL plano sin reescribir la lógica: un constructor de consultas traduce a SQL parametrizado sobre pg la misma interfaz encadenable, estilo PostgREST, que usa todo el código. Como cada acceso a datos pasa por cuatro fábricas de clientes, cambiar el cliente bastó para mover la aplicación entera sin tocar reglas de negocio.
- La comisión de PayPhone se traslada dividiendo, no sumando: con las tarifas publicadas, la pasarela se queda con un 5,75% de lo que cobra, así que sumarle ese porcentaje a $100 cobra $105,75 y deja $99,67. Dividiendo se cobran $106,10 y a la tienda le llegan exactamente $100, calculado al centavo para no cobrarle de más al comprador.
- Primero lo gratis: para completar los datos del comprador, la cédula o el RUC se buscan en checkouts anteriores, en pedidos y en el padrón del taller, y solo si nadie lo conoce se consulta un registro externo que cobra por cada consulta.
- El envío se cobra por producto y por unidad, no por pedido: un producto puede traer su propio costo y el resto paga la tarifa del destino. Un 0 significa «viaja gratis» y el vacío cae en la tarifa, y la misma función calcula lo que muestra el carrito y lo que se guarda en el pedido.
- Los estados del pedido son los mismos para envío y retiro, pero se nombran según el caso: un pedido que el cliente pasa a recoger no figura como «Enviado» sino como «Listo para retirar». Partir los estados en dos habría roto el historial, los filtros y las consultas.
Retos
- Proteger la única consulta pública que toca la base sin sesión: 60 pedidos simultáneos al seguimiento llevaban la portada de 1,3 s a 7,0 s. Quedó limitada a 30 consultas por minuto por IP, a 3 conexiones de un pool de 10 y a 15 segundos de memoria, así una avalancha vuelve lenta esa página y no deja al catálogo ni al checkout sin conexiones.
- Que una falla del proveedor no vacíe la vitrina: una página vacía devuelta con HTTP 200 puede confundirse con el final del catálogo. Si una pasada intenta desactivar más del 30% de los productos activos - y más de 50 -, la baja se cancela y queda registrada; y un producto sin imagen espera en borrador hasta que llega una.
- Descargar imágenes de un tercero sin abrirle una puerta al servidor: solo HTTPS, nada de localhost ni redes privadas, cada redirección revalidada con un máximo de tres, 20 segundos y 12 MB por archivo, y solo tipos de imagen. Lo que pasa se convierte a WebP y se aloja en R2, con hasta 3 imágenes por producto.
- Recuperar la galería que la migración original había dejado atrás: en Stock Manager Advance las fotos secundarias vivían en una segunda tabla que no se leyó. Se recuperaron sin alterar ninguna imagen principal.
Resultado
La tienda corre en producción en Railway - su API y su web - sobre el mismo PostgreSQL que el taller. El catálogo se actualiza desde el mayorista dentro del horario que fija el negocio, respetando lo que se fijó a mano; el cliente paga con PayPhone, transferencia o efectivo, y quien ya pasó por el taller encuentra sus datos cargados al comprar. La tienda es también la puerta del servicio técnico: recibe solicitudes por WhatsApp y muestra en qué va cada reparación, sin llamadas y sin crear una cuenta.