Saltar al contenido
Caso · 12 / 15← Todos los trabajos

Tiendas

Un core de tienda online y un CLI que lo convierte en la tienda de un cliente nuevo. Hoy corre Rodar MDQ y BiciTienda MDQ.

Rol
Arquitectura y desarrollo completo
Stack
Next.js 16, TypeScript, Tailwind 4, Drizzle, Neon Postgres / PGlite, React Email, Go
El starter, como Faro
El starter, como FaroLa plantilla se genera desde una tienda real
(01) El problema

Los comercios de Mar del Plata pedían siempre lo mismo: catálogo, carrito, checkout, pedidos y un panel que puedan manejar solos. La primera, 3:23, era un frontend con datos de prueba. Armar cada tienda desde cero llevaba semanas, y copiar la anterior a mano arrastraba la marca, los textos y las fotos del cliente anterior.

Mi rolSeparé las tiendas en un core común y una capa chica por tienda, y escribí el CLI que genera una tienda nueva a partir de eso.
(02) ResultadosContados en el código
2tiendas de clientes en producción con el mismo core
11archivos que cambia una tienda nueva. Todo lo demás es core
6integraciones con reemplazo local, así una tienda corre sin credenciales
(03) Arquitectura

Tres decisiones que lo definieron.

  1. 01

    La plantilla se genera desde una tienda real

    Por qué. Rodar MDQ es la tienda de referencia. El CLI exporta su último commit con git archive, saca las fotos, los textos y las URLs de Cloudinary de Rodar, pone encima una marca de relleno llamada Faro y verifica que lleguen todas las migraciones y los scripts de base. El starter nunca se edita a mano, así que no se aleja del código que corre en producción.

    El costo. Un arreglo del core tiene que entrar primero en Rodar. Algunos restos de Rodar en archivos del core se reemplazan con una lista de textos, que sólo avisa cuando un texto ya no está.

  2. 02

    Copiar el core, no compartir un paquete

    Por qué. new-store copia el starter en un repo propio, con su base en Neon y su proyecto en Vercel. Las palabras del rubro, las rutas y los módulos viven en la config y en un léxico, así BiciTienda pudo sumar talles y colores, turnos y cuentas de cliente sin tocar Rodar.

    El costo. Un arreglo no llega solo a las tiendas que ya existen. Cada una lo recibe con un cherry-pick a mano.

  3. 03

    Cada integración tiene un reemplazo local

    Por qué. Sin variables de entorno, la tienda usa PGlite en vez de Neon, escribe los mails en una bandeja local, paga con una página de prueba y abre el panel con un PIN de desarrollo. Una tienda nueva corre con migrate, seed y dev, y se la puedo mostrar al cliente antes de que nadie cree una cuenta en ningún lado.

    El costo. Dos caminos de código por integración. La página de pago de prueba tuvo que quedar bloqueada en producción, y PGlite puede esconder una diferencia con Neon hasta el deploy.

(04) GaleríaSeguí scrolleando →
El starter, como Faro
El starter, como Faro · Lo que genera new-store: el core completo con una marca de relleno, productos de ejemplo y dos sucursales de muestra.
Rodar MDQ
Rodar MDQ · La tienda de referencia, de bicis y motos eléctricas. Mismo esqueleto que el starter, con su marca, sus rutas y su catálogo.
BiciTienda MDQ
BiciTienda MDQ · Generada con la identidad carbono y después creció sola: turnos de taller, presupuestos y talles por bici.
Panel compartido
Panel compartido · Cada tienda trae el mismo panel de productos, stock, pedidos y contenido. Acá corriendo en local sobre PGlite con datos de ejemplo.
(05) Qué haría después
01Un comando del CLI que liste los commits del core que le faltan a una tienda desde que se generó, para que los arreglos no dependan de acordarse de cada cherry-pick.
02Pasar 3:23 de los datos de prueba al core, con su base, sus pedidos y su panel.
03Correr new-store en CI con cada cambio de Rodar y verificar que la tienda generada pase tipos, lint y build.
Próximo proyecto · 13 / 15
El Rey Jesús →Sitio y administrador de contenido para una iglesia
Caso · 12 / 15

Tiendas

Un core de tienda online y un CLI que lo convierte en la tienda de un cliente nuevo. Hoy corre Rodar MDQ y BiciTienda MDQ.

Rol
Arquitectura y desarrollo completo
Stack
Next.js 16, TypeScript, Tailwind 4, Drizzle, Neon Postgres / PGlite, React Email, Go
Tiendas
(01) El problema

Los comercios de Mar del Plata pedían siempre lo mismo: catálogo, carrito, checkout, pedidos y un panel que puedan manejar solos. La primera, 3:23, era un frontend con datos de prueba. Armar cada tienda desde cero llevaba semanas, y copiar la anterior a mano arrastraba la marca, los textos y las fotos del cliente anterior.

Mi rolSeparé las tiendas en un core común y una capa chica por tienda, y escribí el CLI que genera una tienda nueva a partir de eso.
(02) Resultados
2tiendas de clientes en producción con el mismo core
11archivos que cambia una tienda nueva. Todo lo demás es core
6integraciones con reemplazo local, así una tienda corre sin credenciales
(03) Arquitectura

Tres decisiones que lo definieron.

01

La plantilla se genera desde una tienda real

Por qué. Rodar MDQ es la tienda de referencia. El CLI exporta su último commit con git archive, saca las fotos, los textos y las URLs de Cloudinary de Rodar, pone encima una marca de relleno llamada Faro y verifica que lleguen todas las migraciones y los scripts de base. El starter nunca se edita a mano, así que no se aleja del código que corre en producción.

El costo. Un arreglo del core tiene que entrar primero en Rodar. Algunos restos de Rodar en archivos del core se reemplazan con una lista de textos, que sólo avisa cuando un texto ya no está.

02

Copiar el core, no compartir un paquete

Por qué. new-store copia el starter en un repo propio, con su base en Neon y su proyecto en Vercel. Las palabras del rubro, las rutas y los módulos viven en la config y en un léxico, así BiciTienda pudo sumar talles y colores, turnos y cuentas de cliente sin tocar Rodar.

El costo. Un arreglo no llega solo a las tiendas que ya existen. Cada una lo recibe con un cherry-pick a mano.

03

Cada integración tiene un reemplazo local

Por qué. Sin variables de entorno, la tienda usa PGlite en vez de Neon, escribe los mails en una bandeja local, paga con una página de prueba y abre el panel con un PIN de desarrollo. Una tienda nueva corre con migrate, seed y dev, y se la puedo mostrar al cliente antes de que nadie cree una cuenta en ningún lado.

El costo. Dos caminos de código por integración. La página de pago de prueba tuvo que quedar bloqueada en producción, y PGlite puede esconder una diferencia con Neon hasta el deploy.

(04) Galería
El starter, como Faro
El starter, como Faro · Lo que genera new-store: el core completo con una marca de relleno, productos de ejemplo y dos sucursales de muestra.
Rodar MDQ
Rodar MDQ · La tienda de referencia, de bicis y motos eléctricas. Mismo esqueleto que el starter, con su marca, sus rutas y su catálogo.
BiciTienda MDQ
BiciTienda MDQ · Generada con la identidad carbono y después creció sola: turnos de taller, presupuestos y talles por bici.
Panel compartido
Panel compartido · Cada tienda trae el mismo panel de productos, stock, pedidos y contenido. Acá corriendo en local sobre PGlite con datos de ejemplo.
(05) Qué haría después
01Un comando del CLI que liste los commits del core que le faltan a una tienda desde que se generó, para que los arreglos no dependan de acordarse de cada cherry-pick.
02Pasar 3:23 de los datos de prueba al core, con su base, sus pedidos y su panel.
03Correr new-store en CI con cada cambio de Rodar y verificar que la tienda generada pase tipos, lint y build.
Próximo proyectoEl Rey Jesús →
Nahuel SantillánES